This commit is contained in:
2026-06-14 15:54:35 +08:00
commit 3caeb07e54
2804 changed files with 373231 additions and 0 deletions
@@ -0,0 +1,45 @@
#include "ElaBaseListView.h"
#include <QMouseEvent>
#include "ElaScrollBar.h"
ElaBaseListView::ElaBaseListView(QWidget* parent)
: QListView(parent)
{
setObjectName("ElaBaseListView");
setStyleSheet(
"ElaBaseListView{background-color: transparent;border:0px;}"
"ElaBaseListView::item{border:none;}");
setAutoScroll(false);
setFocusPolicy(Qt::NoFocus);
setVerticalScrollBar(new ElaScrollBar(this));
setHorizontalScrollBar(new ElaScrollBar(this));
setSelectionMode(QAbstractItemView::NoSelection);
setMouseTracking(true);
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
ElaBaseListView::~ElaBaseListView()
{
}
void ElaBaseListView::mousePressEvent(QMouseEvent* event)
{
Q_EMIT mousePress(indexAt(event->pos()));
QListView::mousePressEvent(event);
}
void ElaBaseListView::mouseReleaseEvent(QMouseEvent* event)
{
Q_EMIT mouseRelease(indexAt(event->pos()));
QListView::mouseReleaseEvent(event);
}
void ElaBaseListView::mouseDoubleClickEvent(QMouseEvent* event)
{
Q_EMIT mouseDoubleClick(indexAt(event->pos()));
QListView::mouseDoubleClickEvent(event);
}
@@ -0,0 +1,25 @@
#ifndef ELABASELISTVIEW_H
#define ELABASELISTVIEW_H
#include <QListView>
#include <QModelIndex>
class ElaScrollBar;
class ElaBaseListView : public QListView
{
Q_OBJECT
public:
explicit ElaBaseListView(QWidget* parent = nullptr);
~ElaBaseListView();
Q_SIGNALS:
Q_SIGNAL void mousePress(const QModelIndex& index);
Q_SIGNAL void mouseRelease(const QModelIndex& index);
Q_SIGNAL void mouseDoubleClick(const QModelIndex& index);
protected:
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void mouseDoubleClickEvent(QMouseEvent* event) override;
};
#endif // ELABASELISTVIEW_H
@@ -0,0 +1,57 @@
#include "ElaBreadcrumbBarDelegate.h"
#include <QPainter>
#include "ElaTheme.h"
ElaBreadcrumbBarDelegate::ElaBreadcrumbBarDelegate(QObject* parent)
: QStyledItemDelegate{parent}
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaBreadcrumbBarDelegate::~ElaBreadcrumbBarDelegate()
{
}
void ElaBreadcrumbBarDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter->setPen(ElaThemeColor(_themeMode, BasicText));
QRect itemRect = option.rect;
QString breadcrumbDisplayData = index.data(Qt::DisplayRole).toString();
QString breadcrumbUserData = index.data(Qt::UserRole).toString();
if (breadcrumbUserData != "LastBreadcrumb")
{
if (_pPressIndex == index)
{
//鼠标按下
painter->setPen(ElaThemeColor(_themeMode, BasicTextPress));
}
else
{
//不为最后一个 且没有被鼠标覆盖
if (!(option.state & QStyle::State_MouseOver))
{
painter->setPen(ElaThemeColor(_themeMode, BasicTextNoFocus));
}
}
}
if (breadcrumbDisplayData != ">")
{
painter->drawText(itemRect, Qt::AlignVCenter | Qt::AlignLeft, breadcrumbDisplayData);
}
else
{
//分隔符
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(painter->font().pixelSize() * 0.785);
painter->setFont(iconFont);
itemRect.setX(itemRect.x() - itemRect.width() * 0.36);
painter->drawText(itemRect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::AngleRight));
}
painter->restore();
}
@@ -0,0 +1,23 @@
#ifndef ELABREADCRUMBBARDELEGATE_H
#define ELABREADCRUMBBARDELEGATE_H
#include <QModelIndex>
#include <QStyledItemDelegate>
#include "Def.h"
class ElaBreadcrumbBarDelegate : public QStyledItemDelegate
{
Q_OBJECT
Q_PRIVATE_CREATE(QModelIndex, PressIndex)
public:
explicit ElaBreadcrumbBarDelegate(QObject* parent = nullptr);
~ElaBreadcrumbBarDelegate();
protected:
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELABREADCRUMBBARDELEGATE_H
@@ -0,0 +1,108 @@
#include "ElaBreadcrumbBarModel.h"
ElaBreadcrumbBarModel::ElaBreadcrumbBarModel(QObject* parent)
: QAbstractListModel{parent}
{
}
ElaBreadcrumbBarModel::~ElaBreadcrumbBarModel()
{
}
int ElaBreadcrumbBarModel::rowCount(const QModelIndex& parent) const
{
return _breadcrumbList.count() * 2 - 1;
}
QVariant ElaBreadcrumbBarModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole)
{
if (index.row() % 2 == 0)
{
return _breadcrumbList[index.row() / 2];
}
else
{
return ">";
}
}
else if (role == Qt::UserRole)
{
if (index.row() == _breadcrumbList.count() * 2 - 2 || index.row() == _breadcrumbList.count() * 2 - 3)
{
return QString("LastBreadcrumb");
}
}
return QVariant();
}
void ElaBreadcrumbBarModel::appendBreadcrumb(QString breadcrumb)
{
if (!breadcrumb.isEmpty())
{
if (_breadcrumbList.count() && _breadcrumbList.last() == breadcrumb)
{
return;
}
if (_breadcrumbList.count() >= 2 && _breadcrumbList[_breadcrumbList.count() - 2] == breadcrumb)
{
beginResetModel();
_breadcrumbList.removeLast();
endResetModel();
return;
}
beginResetModel();
_breadcrumbList.append(breadcrumb);
endResetModel();
}
}
void ElaBreadcrumbBarModel::removeBreadcrumb(QString breadcrumb)
{
if (_breadcrumbList.contains(breadcrumb))
{
beginResetModel();
_breadcrumbList.removeAt(_breadcrumbList.lastIndexOf(breadcrumb));
endResetModel();
}
}
void ElaBreadcrumbBarModel::removeBreadcrumb(int index)
{
if (index >= _breadcrumbList.count())
{
return;
}
beginResetModel();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
_breadcrumbList.remove(index, _breadcrumbList.count() - index);
#else
for (int i = _breadcrumbList.count() - 1; i >= 0; i--)
{
if (i < index)
{
break;
}
_breadcrumbList.removeAt(i);
}
#endif
endResetModel();
}
void ElaBreadcrumbBarModel::setBreadcrumbList(QStringList breadcrumbList)
{
beginResetModel();
this->_breadcrumbList = breadcrumbList;
endResetModel();
}
int ElaBreadcrumbBarModel::getBreadcrumbListCount()
{
return _breadcrumbList.count();
}
QStringList ElaBreadcrumbBarModel::getBreadcrumbList()
{
return _breadcrumbList;
}
@@ -0,0 +1,30 @@
#ifndef ELABREADCRUMBBARMODEL_H
#define ELABREADCRUMBBARMODEL_H
#include <QAbstractListModel>
class ElaBreadcrumbBarModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ElaBreadcrumbBarModel(QObject* parent = nullptr);
~ElaBreadcrumbBarModel();
void appendBreadcrumb(QString breadcrumb);
void removeBreadcrumb(QString breadcrumb);
void removeBreadcrumb(int index);
void setBreadcrumbList(QStringList breadcrumbList);
int getBreadcrumbListCount();
QStringList getBreadcrumbList();
protected:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
private:
QStringList _breadcrumbList;
};
#endif // ELABREADCRUMBBARMODEL_H
@@ -0,0 +1,187 @@
#include "ElaCalendarDelegate.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaCalendarDelegate::ElaCalendarDelegate(ElaCalendarModel* calendarModel, QObject* parent)
: QStyledItemDelegate{parent}
{
_pIsTransparent = false;
_calendarModel = calendarModel;
_pItemWidth = 42;
_pItemHeight = 42;
_nowDate = QDate::currentDate();
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
connect(_calendarModel, &ElaCalendarModel::displayModeChanged, this, &ElaCalendarDelegate::onCalendarModelDisplayModeChanged);
}
ElaCalendarDelegate::~ElaCalendarDelegate()
{
}
void ElaCalendarDelegate::onCalendarModelDisplayModeChanged()
{
switch (_calendarModel->getDisplayMode())
{
case YearMode:
case MonthMode:
{
_pItemWidth = 53;
_pItemHeight = 60;
break;
}
case DayMode:
{
_pItemWidth = 42;
_pItemHeight = 42;
break;
}
}
}
void ElaCalendarDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
if (_pIsTransparent)
{
return;
}
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
ElaCalendarType displayModel = _calendarModel->getDisplayMode();
switch (displayModel)
{
case YearMode:
case MonthMode:
{
_drawYearOrMonth(painter, option, index);
break;
}
case DayMode:
{
_drawDays(painter, option, index);
break;
}
}
painter->restore();
QStyledItemDelegate::paint(painter, option, index);
}
QSize ElaCalendarDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QSize(_pItemWidth, _pItemHeight);
}
void ElaCalendarDelegate::_drawYearOrMonth(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QRectF itemRect = option.rect;
bool isNow = false;
ElaCalendarData data = index.data(Qt::UserRole).value<ElaCalendarData>();
qreal baseRadius = _pItemWidth * 0.5;
// 当前日期绘制
ElaCalendarType displayMode = _calendarModel->getDisplayMode();
if ((displayMode == ElaCalendarType::YearMode && data.year == _nowDate.year()) || (displayMode == ElaCalendarType::MonthMode && data.month == _nowDate.month() && data.year == _nowDate.year()))
{
isNow = true;
QColor drawColor = option.state.testFlag(QStyle::State_MouseOver) ? ElaThemeColor(_themeMode, PrimaryHover) : ElaThemeColor(_themeMode, PrimaryNormal);
painter->setPen(Qt::NoPen);
painter->setBrush(drawColor);
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
}
else
{
// 覆盖和选中效果绘制
if (option.state.testFlag(QStyle::State_MouseOver))
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicHover));
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
}
}
// 文字绘制
painter->setPen(isNow ? ElaThemeColor(_themeMode, BasicTextInvert) : ElaThemeColor(_themeMode, BasicText));
painter->drawText(itemRect, Qt::AlignCenter, displayMode == ElaCalendarType::YearMode ? QString::number(data.year) : QString::number(data.month));
QString desText = data.desText;
if (!desText.isEmpty())
{
itemRect.adjust(0, 10, 0, 0);
QFont font = painter->font();
font.setPixelSize(9);
painter->setFont(font);
painter->drawText(itemRect, Qt::AlignTop | Qt::AlignHCenter, desText);
}
}
void ElaCalendarDelegate::_drawDays(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
qreal penWidth = 1.5;
qreal baseRadius = _pItemWidth * 0.5 - penWidth;
QVariant variant = index.data(Qt::UserRole);
if (variant.isValid())
{
QRectF itemRect = option.rect;
bool isNow = false;
ElaCalendarData data = variant.value<ElaCalendarData>();
// 当前日期绘制
if (data.year == _nowDate.year() && data.month == _nowDate.month() && data.day == _nowDate.day())
{
isNow = true;
QColor drawColor = option.state.testFlag(QStyle::State_MouseOver) ? ElaThemeColor(_themeMode, PrimaryHover) : ElaThemeColor(_themeMode, PrimaryNormal);
if (option.state.testFlag(QStyle::State_Selected))
{
painter->setPen(QPen(drawColor, penWidth));
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
painter->setBrush(drawColor);
painter->setPen(Qt::NoPen);
painter->drawEllipse(itemRect.center(), baseRadius - 2 * penWidth, baseRadius - 2 * penWidth);
}
else
{
painter->setPen(Qt::NoPen);
painter->setBrush(drawColor);
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
}
}
else
{
// 覆盖和选中效果绘制
if (option.state.testFlag(QStyle::State_Selected))
{
painter->setPen(QPen(option.state.testFlag(QStyle::State_MouseOver) ? ElaThemeColor(_themeMode, PrimaryHover) : ElaThemeColor(_themeMode, PrimaryNormal), penWidth));
painter->setBrush(Qt::NoBrush);
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
}
if (option.state.testFlag(QStyle::State_MouseOver))
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicHover));
if (option.state.testFlag(QStyle::State_Selected))
{
painter->drawEllipse(itemRect.center(), baseRadius - penWidth, baseRadius - penWidth);
}
else
{
painter->drawEllipse(itemRect.center(), baseRadius, baseRadius);
}
}
}
// 文字绘制
painter->setPen(isNow ? ElaThemeColor(_themeMode, BasicTextInvert) : ElaThemeColor(_themeMode, BasicText));
painter->drawText(itemRect, Qt::AlignCenter, QString::number(data.day));
QString desText = data.desText;
if (!desText.isEmpty())
{
itemRect.adjust(0, 2 * penWidth, 0, 0);
QFont font = painter->font();
font.setPixelSize(9);
painter->setFont(font);
painter->drawText(itemRect, Qt::AlignTop | Qt::AlignHCenter, desText);
}
}
}
@@ -0,0 +1,32 @@
#ifndef ELACALENDARDELEGATE_H
#define ELACALENDARDELEGATE_H
#include <QDate>
#include <QStyledItemDelegate>
#include "Def.h"
#include "ElaCalendarModel.h"
class ElaCalendarDelegate : public QStyledItemDelegate
{
Q_OBJECT
Q_PRIVATE_CREATE(int, ItemWidth)
Q_PRIVATE_CREATE(int, ItemHeight)
Q_PRIVATE_CREATE(bool, IsTransparent)
public:
explicit ElaCalendarDelegate(ElaCalendarModel* calendarModel, QObject* parent = nullptr);
~ElaCalendarDelegate();
Q_SLOT void onCalendarModelDisplayModeChanged();
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
ElaCalendarModel* _calendarModel{nullptr};
ElaThemeType::ThemeMode _themeMode;
QDate _nowDate;
void _drawYearOrMonth(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
void _drawDays(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
};
#endif // ELACALENDARDELEGATE_H
@@ -0,0 +1,152 @@
#include "ElaCalendarModel.h"
ElaCalendarModel::ElaCalendarModel(QObject* parent)
: QAbstractListModel{parent}
{
_pMinimumDate.setDate(1924, 1, 1);
_pMaximumDate.setDate(2124, 12, 31);
_initRowCount();
}
ElaCalendarModel::~ElaCalendarModel()
{
}
void ElaCalendarModel::setMinimumDate(QDate minimudate)
{
_pMinimumDate = minimudate;
_initRowCount();
}
QDate ElaCalendarModel::getMinimumDate() const
{
return _pMinimumDate;
}
void ElaCalendarModel::setMaximumDate(QDate maximumDate)
{
_pMaximumDate = maximumDate;
_initRowCount();
}
QDate ElaCalendarModel::getMaximumDate() const
{
return _pMaximumDate;
}
void ElaCalendarModel::setDisplayMode(ElaCalendarType displayMode)
{
beginResetModel();
_displayMode = displayMode;
endResetModel();
Q_EMIT displayModeChanged();
}
ElaCalendarType ElaCalendarModel::getDisplayMode() const
{
return _displayMode;
}
QModelIndex ElaCalendarModel::getIndexFromDate(QDate date)
{
switch (_displayMode)
{
case YearMode:
{
return this->index(date.year() - _pMinimumDate.year());
}
case MonthMode:
{
return this->index((date.year() - _pMinimumDate.year()) * 12 + date.month() - 1);
}
case DayMode:
{
return this->index(_pMinimumDate.daysTo(date) + _offset);
}
}
return QModelIndex();
}
QDate ElaCalendarModel::getDateFromIndex(const QModelIndex& index) const
{
if (!index.isValid() || index.row() < _offset)
{
return QDate();
}
return _pMinimumDate.addDays(index.row() - _offset);
}
QVariant ElaCalendarModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::UserRole)
{
switch (_displayMode)
{
case YearMode:
{
return QVariant::fromValue<ElaCalendarData>(ElaCalendarData(_pMinimumDate.year() + index.row(), 1, 1));
}
case MonthMode:
{
int year = _pMinimumDate.year() + index.row() / 12;
int month = index.row() % 12 + 1;
if (month == 1)
{
return QVariant::fromValue<ElaCalendarData>(ElaCalendarData(year, month, 1, QString::number(year)));
}
else
{
return QVariant::fromValue<ElaCalendarData>(ElaCalendarData(_pMinimumDate.year() + index.row() / 12, month, 1));
}
}
case DayMode:
{
if (index.row() >= _offset)
{
QDate date = getDateFromIndex(index);
if (date.day() == 1)
{
return QVariant::fromValue<ElaCalendarData>(ElaCalendarData(date.year(), date.month(), date.day(), QString("%1月").arg(date.month())));
}
else
{
return QVariant::fromValue<ElaCalendarData>(ElaCalendarData(date.year(), date.month(), date.day()));
}
}
}
}
}
return QVariant();
}
int ElaCalendarModel::rowCount(const QModelIndex& parent) const
{
switch (_displayMode)
{
case YearMode:
{
return _pMaximumDate.year() - _pMinimumDate.year() + 1;
}
case MonthMode:
{
return (_pMaximumDate.year() - _pMinimumDate.year() + 1) * 12;
}
case DayMode:
{
return _dayRowCount;
}
}
return 0;
}
void ElaCalendarModel::_initRowCount()
{
_dayRowCount = _pMinimumDate.daysTo(_pMaximumDate);
_offset = _pMinimumDate.dayOfWeek();
_dayRowCount += _offset + 1;
}
int ElaCalendarModel::_getCurrentDay(int row) const
{
return _pMinimumDate.addDays(row - _offset).day();
}
@@ -0,0 +1,70 @@
#ifndef ELACALENDARMODEL_H
#define ELACALENDARMODEL_H
#include <QAbstractListModel>
#include <QDate>
#include <QMetaType>
#include "stdafx.h"
enum ElaCalendarType
{
YearMode = 0x0001,
MonthMode = 0x0002,
DayMode = 0x0003,
};
struct ElaCalendarData : public QObjectData
{
public:
ElaCalendarData(){};
~ElaCalendarData(){};
ElaCalendarData(int year, int month, int day, QString desText = "")
: year(year), month(month), day(day), desText(desText){};
ElaCalendarData(const ElaCalendarData& other)
{
year = other.year;
month = other.month;
day = other.day;
desText = other.desText;
}
int year = 1924;
int month = 1;
int day = 1;
QString desText{""};
};
Q_DECLARE_METATYPE(ElaCalendarData);
class ElaCalendarModel : public QAbstractListModel
{
Q_OBJECT
Q_PRIVATE_CREATE_Q_H(QDate, MinimumDate)
Q_PRIVATE_CREATE_Q_H(QDate, MaximumDate)
public:
explicit ElaCalendarModel(QObject* parent = nullptr);
~ElaCalendarModel();
void setDisplayMode(ElaCalendarType displayType);
ElaCalendarType getDisplayMode() const;
QModelIndex getIndexFromDate(QDate date);
QDate getDateFromIndex(const QModelIndex& index) const;
virtual QVariant data(const QModelIndex& index, int role) const override;
Q_SIGNALS:
Q_SIGNAL void currentYearMonthChanged(QString date);
Q_SIGNAL void displayModeChanged();
protected:
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
private:
int _offset{0};
QDate _pMinimumDate;
QDate _pMaximumDate;
ElaCalendarType _displayMode{ElaCalendarType::DayMode};
int _dayRowCount{0};
void _initRowCount();
int _getCurrentDay(int row) const;
};
#endif // ELACALENDARMODEL_H
@@ -0,0 +1,29 @@
#include "ElaCalendarPickerContainer.h"
#include <QPainter>
#include "ElaTheme.h"
ElaCalendarPickerContainer::ElaCalendarPickerContainer(QWidget* parent)
: QWidget{parent}
{
setWindowFlags(Qt::FramelessWindowHint | Qt::Popup | Qt::NoDropShadowWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
setContentsMargins(0, 0, 0, 0);
setObjectName("ElaCalendarPickerContainer");
setStyleSheet("#ElaCalendarPickerContainer{background-color:transparent}");
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaCalendarPickerContainer::~ElaCalendarPickerContainer()
{
}
void ElaCalendarPickerContainer::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::Antialiasing);
eTheme->drawEffectShadow(&painter, rect(), 6, 5);
painter.restore();
}
@@ -0,0 +1,21 @@
#ifndef ELACALENDARPICKERCONTAINER_H
#define ELACALENDARPICKERCONTAINER_H
#include <QWidget>
#include "Def.h"
class ElaCalendarPickerContainer : public QWidget
{
Q_OBJECT
public:
explicit ElaCalendarPickerContainer(QWidget* parent = nullptr);
~ElaCalendarPickerContainer();
protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELACALENDARPICKERCONTAINER_H
@@ -0,0 +1,43 @@
#include "ElaCalendarTitleDelegate.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaCalendarTitleDelegate::ElaCalendarTitleDelegate(QObject* parent)
: QStyledItemDelegate{parent}
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaCalendarTitleDelegate::~ElaCalendarTitleDelegate()
{
}
void ElaCalendarTitleDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
QRectF itemRect = option.rect;
// 文字绘制
QString title = index.data(Qt::UserRole).toString();
if (!title.isEmpty())
{
painter->setPen(ElaThemeColor(_themeMode, BasicText));
QFont font = painter->font();
font.setWeight(QFont::Bold);
painter->setFont(font);
painter->drawText(itemRect, Qt::AlignCenter, title);
}
painter->restore();
QStyledItemDelegate::paint(painter, option, index);
}
QSize ElaCalendarTitleDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QSize(42, 30);
}
@@ -0,0 +1,21 @@
#ifndef ELACALENDARTITLEDELEGATE_H
#define ELACALENDARTITLEDELEGATE_H
#include <QStyledItemDelegate>
#include "Def.h"
class ElaCalendarTitleDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ElaCalendarTitleDelegate(QObject* parent = nullptr);
~ElaCalendarTitleDelegate();
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELACALENDARTITLEDELEGATE_H
@@ -0,0 +1,54 @@
#include "ElaCalendarTitleModel.h"
ElaCalendarTitleModel::ElaCalendarTitleModel(QObject* parent)
: QAbstractListModel{parent}
{
}
ElaCalendarTitleModel::~ElaCalendarTitleModel()
{
}
int ElaCalendarTitleModel::rowCount(const QModelIndex& parent) const
{
return 7;
}
QVariant ElaCalendarTitleModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::UserRole)
{
switch (index.row())
{
case 0:
{
return tr("");
}
case 1:
{
return tr("");
}
case 2:
{
return tr("");
}
case 3:
{
return tr("");
}
case 4:
{
return tr("");
}
case 5:
{
return tr("");
}
case 6:
{
return tr("");
}
}
}
return QVariant();
}
@@ -0,0 +1,18 @@
#ifndef ELACALENDARTITLEMODEL_H
#define ELACALENDARTITLEMODEL_H
#include <QAbstractListModel>
class ElaCalendarTitleModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ElaCalendarTitleModel(QObject* parent = nullptr);
~ElaCalendarTitleModel();
protected:
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex& index, int role) const override;
};
#endif // ELACALENDARTITLEMODEL_H
@@ -0,0 +1,63 @@
#include "ElaCentralStackedWidget.h"
#include <QPainter>
#include <QPainterPath>
#include "ElaTheme.h"
ElaCentralStackedWidget::ElaCentralStackedWidget(QWidget* parent)
: QStackedWidget(parent)
{
setObjectName("ElaCentralStackedWidget");
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, &ElaCentralStackedWidget::onThemeModeChanged);
}
ElaCentralStackedWidget::~ElaCentralStackedWidget()
{
}
void ElaCentralStackedWidget::onThemeModeChanged(ElaThemeType::ThemeMode themeMode)
{
_themeMode = themeMode;
}
void ElaCentralStackedWidget::setIsTransparent(bool isTransparent)
{
this->_isTransparent = isTransparent;
update();
}
bool ElaCentralStackedWidget::getIsTransparent() const
{
return _isTransparent;
}
void ElaCentralStackedWidget::setIsHasRadius(bool isHasRadius)
{
this->_isHasRadius = isHasRadius;
update();
}
void ElaCentralStackedWidget::paintEvent(QPaintEvent* event)
{
if (!_isTransparent)
{
QPainter painter(this);
QRect targetRect = this->rect();
targetRect.adjust(1, 1, 10, 10);
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(ElaThemeColor(_themeMode, BasicBaseLine), 1.5));
painter.setBrush(ElaThemeColor(_themeMode, WindowCentralStackBase));
if (_isHasRadius)
{
painter.drawRoundedRect(targetRect, 10, 10);
}
else
{
painter.drawRect(targetRect);
}
painter.restore();
}
QStackedWidget::paintEvent(event);
}
@@ -0,0 +1,29 @@
#ifndef ELACENTRALSTACKEDWIDGET_H
#define ELACENTRALSTACKEDWIDGET_H
#include <QStackedWidget>
#include "Def.h"
class ElaCentralStackedWidget : public QStackedWidget
{
Q_OBJECT
public:
explicit ElaCentralStackedWidget(QWidget* parent = nullptr);
~ElaCentralStackedWidget();
Q_SLOT void onThemeModeChanged(ElaThemeType::ThemeMode themeMode);
void setIsTransparent(bool isTransparent);
bool getIsTransparent() const;
void setIsHasRadius(bool isHasRadius);
protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
ElaThemeType::ThemeMode _themeMode;
bool _isTransparent{false};
bool _isHasRadius{true};
};
#endif // ELACENTRALSTACKEDWIDGET_H
@@ -0,0 +1,131 @@
#include "ElaCheckBoxStyle.h"
#include <QDebug>
#include <QPainter>
#include <QStyleOption>
#include "ElaTheme.h"
ElaCheckBoxStyle::ElaCheckBoxStyle(QStyle* style)
{
_pCheckIndicatorWidth = 21;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaCheckBoxStyle::~ElaCheckBoxStyle()
{
}
void ElaCheckBoxStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
// qDebug() << element << option->rect;
switch (element)
{
case QStyle::CE_CheckBox:
{
if (const QStyleOptionButton* bopt = qstyleoption_cast<const QStyleOptionButton*>(option))
{
bool isEnabled = bopt->state.testFlag(QStyle::State_Enabled);
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
QRect checkBoxRect = bopt->rect;
QRect checkRect(checkBoxRect.x(), checkBoxRect.y(), _pCheckIndicatorWidth, _pCheckIndicatorWidth);
checkRect.adjust(1, 1, -1, -1);
//复选框绘制
painter->setPen(Qt::NoPen);
if (bopt->state.testFlag(QStyle::State_On) || bopt->state.testFlag(QStyle::State_NoChange))
{
painter->setPen(Qt::NoPen);
if (bopt->state.testFlag(QStyle::State_Sunken))
{
painter->setBrush(ElaThemeColor(_themeMode, PrimaryPress));
}
else
{
if (bopt->state.testFlag(QStyle::State_MouseOver))
{
painter->setBrush(ElaThemeColor(_themeMode, PrimaryHover));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
}
}
}
else
{
if (bopt->state.testFlag(QStyle::State_Sunken))
{
painter->setPen(ElaThemeColor(_themeMode, BasicBorderDeep));
}
else
{
painter->setPen(ElaThemeColor(_themeMode, BasicBorderDeep));
if (bopt->state.testFlag(QStyle::State_MouseOver))
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHover));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
}
}
}
painter->drawRoundedRect(checkRect, 2, 2);
//图标绘制
painter->setPen(ElaThemeColor(ElaThemeType::Dark, BasicText));
if (bopt->state.testFlag(QStyle::State_On))
{
painter->save();
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(_pCheckIndicatorWidth * 0.75);
painter->setFont(iconFont);
painter->drawText(checkRect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::Check));
painter->restore();
}
else if (bopt->state.testFlag(QStyle::State_NoChange))
{
QLine checkLine(checkRect.x() + 3, checkRect.center().y(), checkRect.right() - 3, checkRect.center().y());
painter->drawLine(checkLine);
}
//文字绘制
painter->setPen(isEnabled ? ElaThemeColor(_themeMode, BasicText) : ElaThemeColor(_themeMode, BasicTextDisable));
QRect textRect(checkRect.right() + 10, checkBoxRect.y(), checkBoxRect.width(), checkBoxRect.height());
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, bopt->text);
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
int ElaCheckBoxStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
// qDebug() << metric << QProxyStyle::pixelMetric(metric, option, widget);
switch (metric)
{
case QStyle::PM_IndicatorWidth:
{
return _pCheckIndicatorWidth;
}
case QStyle::PM_IndicatorHeight:
{
return _pCheckIndicatorWidth;
}
case QStyle::PM_CheckBoxLabelSpacing:
{
return 10;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
@@ -0,0 +1,21 @@
#ifndef ELACHECKBOXSTYLE_H
#define ELACHECKBOXSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaCheckBoxStyle : public QProxyStyle
{
Q_OBJECT
Q_PRIVATE_CREATE(int, CheckIndicatorWidth)
public:
explicit ElaCheckBoxStyle(QStyle* style = nullptr);
~ElaCheckBoxStyle();
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELACHECKBOXSTYLE_H
@@ -0,0 +1,53 @@
#include "ElaColorDisplayDelegate.h"
#include <QColor>
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaColorDisplayDelegate::ElaColorDisplayDelegate(QObject* parent)
: QStyledItemDelegate{parent}
{
_pThemeMode = eTheme->getThemeMode();
}
ElaColorDisplayDelegate::~ElaColorDisplayDelegate()
{
}
void ElaColorDisplayDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
QRectF itemRect = option.rect;
// 颜色球绘制
QColor displayColor = index.data(Qt::UserRole).value<QColor>();
if (displayColor.isValid())
{
painter->setPen(ElaThemeColor(_pThemeMode, PopupBorderHover));
painter->setBrush(index.data(Qt::UserRole).value<QColor>());
}
else
{
QPen pen(ElaThemeColor(_pThemeMode, PopupBorderHover));
pen.setStyle(Qt::DashLine);
painter->setPen(pen);
}
painter->drawEllipse(itemRect.center(), 10, 10);
// 覆盖效果绘制
if (option.state.testFlag(QStyle::State_MouseOver) || option.state.testFlag(QStyle::State_Selected))
{
painter->setBrush(Qt::NoBrush);
painter->drawEllipse(itemRect.center(), 13, 13);
}
painter->restore();
QStyledItemDelegate::paint(painter, option, index);
}
QSize ElaColorDisplayDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QSize(30, 30);
}
@@ -0,0 +1,19 @@
#ifndef ELACOLORDISPLAYDELEGATE_H
#define ELACOLORDISPLAYDELEGATE_H
#include <QStyledItemDelegate>
#include "Def.h"
class ElaColorDisplayDelegate : public QStyledItemDelegate
{
Q_OBJECT
Q_PRIVATE_CREATE(ElaThemeType::ThemeMode, ThemeMode)
public:
explicit ElaColorDisplayDelegate(QObject* parent = nullptr);
~ElaColorDisplayDelegate();
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
#endif // ELACOLORDISPLAYDELEGATE_H
@@ -0,0 +1,74 @@
#include "ElaColorDisplayModel.h"
ElaColorDisplayModel::ElaColorDisplayModel(QObject* parent)
: QAbstractListModel{parent}
{
}
ElaColorDisplayModel::~ElaColorDisplayModel()
{
}
void ElaColorDisplayModel::appendDisplayColor(QList<QColor> colorList)
{
beginResetModel();
_displayColorList.append(colorList);
endResetModel();
}
void ElaColorDisplayModel::appendDisplayColor(QColor color)
{
beginResetModel();
_displayColorList.append(color);
endResetModel();
}
void ElaColorDisplayModel::removeDisplayColor(int index)
{
if (index < 0 || index >= _displayColorList.count())
{
return;
}
beginResetModel();
_displayColorList.removeAt(index);
endResetModel();
}
void ElaColorDisplayModel::replaceDisplayColor(QColor color, int index)
{
if (index < 0 || index >= _displayColorList.count())
{
return;
}
beginResetModel();
_displayColorList[index] = color;
endResetModel();
}
QList<QColor> ElaColorDisplayModel::getDisplayColorList() const
{
return _displayColorList;
}
QColor ElaColorDisplayModel::getDisplayColor(int index) const
{
if (index < 0 || index >= _displayColorList.count())
{
return QColor();
}
return _displayColorList[index];
}
int ElaColorDisplayModel::rowCount(const QModelIndex& parent) const
{
return _displayColorList.count();
}
QVariant ElaColorDisplayModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::UserRole)
{
return QVariant::fromValue(_displayColorList[index.row()]);
}
return QVariant();
}
@@ -0,0 +1,28 @@
#ifndef ELACOLORDISPLAYMODEL_H
#define ELACOLORDISPLAYMODEL_H
#include <QAbstractListModel>
#include <QColor>
class ElaColorDisplayModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ElaColorDisplayModel(QObject* parent = nullptr);
~ElaColorDisplayModel();
void appendDisplayColor(QList<QColor> colorList);
void appendDisplayColor(QColor color);
void removeDisplayColor(int index);
void replaceDisplayColor(QColor color, int index);
QList<QColor> getDisplayColorList() const;
QColor getDisplayColor(int index) const;
protected:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
private:
QList<QColor> _displayColorList;
};
#endif // ELACOLORDISPLAYMODEL_H
@@ -0,0 +1,120 @@
#include "ElaColorPicker.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include "ElaTheme.h"
ElaColorPicker::ElaColorPicker(QWidget* parent)
: QWidget{parent}
{
setFixedSize(260, 260);
_pThemeMode = eTheme->getThemeMode();
// 初始化色相图
QPixmap ColorPickerPix(QSize(257, 257));
QImage ColorPickerImage = ColorPickerPix.toImage();
for (int y = 0; y < ColorPickerImage.height(); y++)
{
for (int x = 0; x < ColorPickerImage.width(); x++)
{
QColor pixColor;
pixColor.setHsvF((qreal)1 / ColorPickerPix.width() * x, 1 - (qreal)1 / ColorPickerPix.height() * y, 1);
pixColor = pixColor.toRgb();
ColorPickerImage.setPixelColor(x, y, pixColor);
}
}
_colorPickerImage = ColorPickerImage;
}
ElaColorPicker::~ElaColorPicker()
{
}
void ElaColorPicker::setSelectedColor(QColor color)
{
_selectedColor = color;
QColor hsvColor = color.toHsv();
_selectedPoint = QPoint(257 * hsvColor.hue() / (qreal)360, 255 - 257 * hsvColor.saturation() / (qreal)255);
update();
}
QColor ElaColorPicker::getSelectedColor() const
{
return _selectedColor;
}
void ElaColorPicker::mousePressEvent(QMouseEvent* event)
{
_selectedPoint = _adjustPointLimit(event->pos());
_selectedColor = _colorPickerImage.pixelColor(_selectedPoint);
Q_EMIT selectedColorChanged(_selectedColor);
QWidget::mousePressEvent(event);
update();
}
void ElaColorPicker::mouseReleaseEvent(QMouseEvent* event)
{
_selectedPoint = _adjustPointLimit(event->pos());
_selectedColor = _colorPickerImage.pixelColor(_selectedPoint);
Q_EMIT selectedColorChanged(_selectedColor);
QWidget::mouseReleaseEvent(event);
update();
}
void ElaColorPicker::mouseMoveEvent(QMouseEvent* event)
{
_selectedPoint = _adjustPointLimit(event->pos());
_selectedColor = _colorPickerImage.pixelColor(_selectedPoint);
Q_EMIT selectedColorChanged(_selectedColor);
QWidget::mouseMoveEvent(event);
update();
}
void ElaColorPicker::paintEvent(QPaintEvent* event)
{
int penWidth = 3;
int borderRadius = 5;
QPainter painter(this);
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
// 色相图绘制
QRect pickerRect = rect();
pickerRect.adjust(penWidth, penWidth, -penWidth, -penWidth);
painter.setPen(QPen(ElaThemeColor(_pThemeMode, BasicBorder), penWidth));
painter.drawRoundedRect(pickerRect, borderRadius, borderRadius);
QPainterPath path;
path.addRoundedRect(pickerRect, borderRadius, borderRadius);
painter.setClipPath(path);
painter.drawImage(pickerRect, _colorPickerImage);
// 取色点绘制
if (!_selectedPoint.isNull())
{
painter.setPen(QPen(Qt::black, 2));
painter.setBrush(Qt::NoBrush);
painter.drawEllipse(_selectedPoint, 8, 8);
}
painter.restore();
}
QPoint ElaColorPicker::_adjustPointLimit(QPoint point)
{
QRect pickerRect = rect();
if (point.x() < 3)
{
point.setX(3);
}
else if (point.x() > pickerRect.right() - 3)
{
point.setX(pickerRect.right() - 3);
}
if (point.y() < 3)
{
point.setY(3);
}
else if (point.y() > pickerRect.bottom() - 3)
{
point.setY(pickerRect.bottom() - 3);
}
return point;
}
@@ -0,0 +1,36 @@
#ifndef ELACOLORPICKER_H
#define ELACOLORPICKER_H
#include <QPixmap>
#include <QWidget>
#include "Def.h"
class ElaColorPicker : public QWidget
{
Q_OBJECT
Q_PRIVATE_CREATE(ElaThemeType::ThemeMode, ThemeMode)
public:
explicit ElaColorPicker(QWidget* parent = nullptr);
~ElaColorPicker();
void setSelectedColor(QColor color);
QColor getSelectedColor() const;
Q_SIGNALS:
Q_SIGNAL void selectedColorChanged(QColor selectedColor);
protected:
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
private:
QImage _colorPickerImage;
QPoint _selectedPoint;
QColor _selectedColor;
QPoint _adjustPointLimit(QPoint point);
};
#endif // ELACOLORPICKER_H
@@ -0,0 +1,31 @@
#include "ElaColorPreview.h"
#include <QPainter>
#include <QPainterPath>
#include "ElaTheme.h"
ElaColorPreview::ElaColorPreview(QWidget* parent)
: QWidget{parent}
{
setFixedSize(50, 260);
_pThemeMode = eTheme->getThemeMode();
}
ElaColorPreview::~ElaColorPreview()
{
}
void ElaColorPreview::paintEvent(QPaintEvent* event)
{
int penWidth = 3;
int borderRadius = 5;
QPainter painter(this);
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
QRect viewRect = rect();
viewRect.adjust(penWidth, penWidth, -penWidth, -penWidth);
painter.setPen(QPen(ElaThemeColor(_pThemeMode, BasicBorder), penWidth));
painter.setBrush(_pBaseColor);
painter.drawRoundedRect(viewRect, borderRadius, borderRadius);
painter.restore();
}
@@ -0,0 +1,20 @@
#ifndef ELACOLORPREVIEW_H
#define ELACOLORPREVIEW_H
#include <QWidget>
#include "Def.h"
class ElaColorPreview : public QWidget
{
Q_OBJECT
Q_PRIVATE_CREATE(QColor, BaseColor)
Q_PRIVATE_CREATE(ElaThemeType::ThemeMode, ThemeMode)
public:
explicit ElaColorPreview(QWidget* parent = nullptr);
~ElaColorPreview();
protected:
virtual void paintEvent(QPaintEvent* event) override;
};
#endif // ELACOLORPREVIEW_H
@@ -0,0 +1,159 @@
#include "ElaColorValueSliderStyle.h"
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyleOptionSlider>
#include "ElaTheme.h"
ElaColorValueSliderStyle::ElaColorValueSliderStyle(QStyle* style)
{
_baseGradient = new QLinearGradient(0, 0, 100, 100);
setProperty("circleRadius", 0.01);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaColorValueSliderStyle::~ElaColorValueSliderStyle()
{
}
void ElaColorValueSliderStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
switch (control)
{
case QStyle::CC_Slider:
{
const QStyleOptionSlider* sopt = qstyleoption_cast<const QStyleOptionSlider*>(option);
if (!sopt)
{
break;
}
_baseGradient->setFinalStop(widget->rect().bottomRight());
QColor highValueColor = _pBaseColor.toHsv();
highValueColor.setHsv(highValueColor.hue(), highValueColor.saturation(), 255);
QColor lowValueColor = _pBaseColor.toHsv();
lowValueColor.setHsv(lowValueColor.hue(), lowValueColor.saturation(), 0);
_baseGradient->setColorAt(0, highValueColor);
_baseGradient->setColorAt(1, lowValueColor);
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QRectF sliderRect = sopt->rect;
sliderRect.adjust(1.5, 0, -1.5, 0);
QRect sliderHandleRect = subControlRect(control, sopt, SC_SliderHandle, widget);
sliderHandleRect.adjust(1, 1, -1, -1);
// 滑槽
painter->setPen(Qt::NoPen);
painter->setBrush(*_baseGradient);
// 渐变背景
painter->drawRoundedRect(QRectF(sliderRect.x(), sliderRect.y() + sliderRect.width() / 8, sliderRect.width(), sliderRect.height() - sliderRect.width() / 4), sliderRect.width() / 2, sliderRect.width() / 2);
// 滑块
// 外圆形
painter->setPen(ElaThemeColor(_themeMode, BasicBorder));
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), sliderHandleRect.width() / 2, sliderHandleRect.width() / 2);
// 内圆形
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
if (_lastState == 0)
{
_lastState = sopt->state;
}
if (_circleRadius == 0)
{
_circleRadius = sliderHandleRect.width() / 3.8;
}
if (sopt->activeSubControls == SC_SliderHandle)
{
if (sopt->state & QStyle::State_Sunken)
{
if (sopt->state & QStyle::State_MouseOver)
{
if (!_lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(sliderHandleRect.width() / 2.8, sliderHandleRect.width() / 4.5, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
}
else
{
if (sopt->state & QStyle::State_MouseOver)
{
if (!_lastState.testFlag(QStyle::State_MouseOver))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 2.8, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
if (_lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 2.8, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
}
}
else
{
if (_lastState.testFlag(QStyle::State_MouseOver) || _lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 3.8, const_cast<QWidget*>(widget));
_lastState &= ~QStyle::State_MouseOver;
_lastState &= ~QStyle::State_Sunken;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
int ElaColorValueSliderStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_SliderLength:
{
return 20;
}
case QStyle::PM_SliderThickness:
{
return 16;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
int ElaColorValueSliderStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const
{
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
{
return Qt::LeftButton;
}
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
void ElaColorValueSliderStyle::_startRadiusAnimation(qreal startRadius, qreal endRadius, QWidget* widget) const
{
ElaColorValueSliderStyle* style = const_cast<ElaColorValueSliderStyle*>(this);
QPropertyAnimation* circleRadiusAnimation = new QPropertyAnimation(style, "circleRadius");
connect(circleRadiusAnimation, &QPropertyAnimation::valueChanged, style, [=](const QVariant& value) {
this->_circleRadius = value.toReal();
widget->update(); });
circleRadiusAnimation->setEasingCurve(QEasingCurve::InOutSine);
circleRadiusAnimation->setStartValue(startRadius);
circleRadiusAnimation->setEndValue(endRadius);
circleRadiusAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
@@ -0,0 +1,27 @@
#ifndef ELACOLORVALUESLIDERSTYLE_H
#define ELACOLORVALUESLIDERSTYLE_H
#include <QLinearGradient>
#include <QProxyStyle>
#include "Def.h"
class ElaColorValueSliderStyle : public QProxyStyle
{
Q_OBJECT
Q_PRIVATE_CREATE(QColor, BaseColor)
public:
explicit ElaColorValueSliderStyle(QStyle* style = nullptr);
~ElaColorValueSliderStyle();
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
QLinearGradient* _baseGradient{nullptr};
mutable QStyle::State _lastState{0};
mutable qreal _circleRadius{0};
void _startRadiusAnimation(qreal startRadius, qreal endRadius, QWidget* widget) const;
};
#endif // ELACOLORVALUESLIDERSTYLE_H
@@ -0,0 +1,247 @@
#include "ElaComboBoxStyle.h"
#include <QDebug>
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaComboBoxStyle::ElaComboBoxStyle(QStyle* style)
{
_pExpandIconRotate = 0;
_pExpandMarkWidth = 0;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaComboBoxStyle::~ElaComboBoxStyle()
{
}
void ElaComboBoxStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_Widget:
{
return;
}
#ifndef Q_OS_WIN
case PE_PanelMenu:
{
return;
}
case PE_IndicatorArrowDown:
{
return;
}
#endif
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaComboBoxStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ComboBoxLabel:
{
return;
}
case QStyle::CE_ShapedFrame:
{
//container区域
if (widget->objectName() == "ElaComboBoxContainer")
{
QRect viewRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
eTheme->drawEffectShadow(painter, viewRect, _shadowBorderWidth, 6);
QRect foregroundRect(viewRect.x() + _shadowBorderWidth, viewRect.y(), viewRect.width() - 2 * _shadowBorderWidth, viewRect.height() - _shadowBorderWidth);
painter->setPen(ElaThemeColor(_themeMode, PopupBorder));
painter->setBrush(ElaThemeColor(_themeMode, PopupBase));
painter->drawRoundedRect(foregroundRect, 3, 3);
painter->restore();
}
return;
}
case QStyle::CE_ItemViewItem:
{
//覆盖高亮
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
int margin = 2;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter->setPen(Qt::NoPen);
QPainterPath path;
QRect optionRect = option->rect;
optionRect.adjust(margin, margin, -margin, -margin);
#ifndef Q_OS_WIN
optionRect.adjust(6, 0, -6, 0);
#endif
path.addRoundedRect(optionRect, 5, 5);
if (option->state & QStyle::State_Selected)
{
if (option->state & QStyle::State_MouseOver)
{
// 选中时覆盖
painter->setBrush(ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
painter->drawPath(path);
}
else
{
// 选中
painter->setBrush(ElaThemeColor(_themeMode, BasicSelectedAlpha));
painter->drawPath(path);
}
//选中Mark
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(optionRect.x() + 3, optionRect.y() + optionRect.height() * 0.2, 3, optionRect.height() - +optionRect.height() * 0.4), 2, 2);
}
else
{
if (option->state & QStyle::State_MouseOver)
{
// 覆盖时颜色
painter->setBrush(ElaThemeColor(_themeMode, BasicHoverAlpha));
painter->drawPath(path);
}
}
// 文字绘制
painter->setPen(ElaThemeColor(_themeMode, BasicText));
painter->drawText(QRect(option->rect.x() + 15, option->rect.y(), option->rect.width() - 15, option->rect.height()), Qt::AlignVCenter, vopt->text);
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
void ElaComboBoxStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
switch (control)
{
case QStyle::CC_ComboBox:
{
//主体显示绘制
if (const QStyleOptionComboBox* copt = qstyleoption_cast<const QStyleOptionComboBox*>(option))
{
painter->save();
painter->setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing);
//背景绘制
bool isEnabled = copt->state.testFlag(QStyle::State_Enabled);
painter->setPen(ElaThemeColor(_themeMode, BasicBorder));
painter->setBrush(isEnabled ? copt->state.testFlag(QStyle::State_MouseOver) ? ElaThemeColor(_themeMode, BasicHover) : ElaThemeColor(_themeMode, BasicBase) : ElaThemeColor(_themeMode, BasicDisable));
QRect comboBoxRect = copt->rect;
comboBoxRect.adjust(_shadowBorderWidth, 1, -_shadowBorderWidth, -1);
painter->drawRoundedRect(comboBoxRect, 3, 3);
// 底边线绘制
painter->setPen(ElaThemeColor(_themeMode, BasicBaseLine));
painter->drawLine(comboBoxRect.x() + 3, comboBoxRect.y() + comboBoxRect.height(), comboBoxRect.x() + comboBoxRect.width() - 3, comboBoxRect.y() + comboBoxRect.height());
//文字绘制
QRect textRect = subControlRect(QStyle::CC_ComboBox, copt, QStyle::SC_ScrollBarSubLine, widget);
painter->setPen(isEnabled ? ElaThemeColor(_themeMode, BasicText) : ElaThemeColor(_themeMode, BasicTextDisable));
painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, copt->currentText);
//展开指示器绘制
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(comboBoxRect.center().x() - _pExpandMarkWidth, comboBoxRect.y() + comboBoxRect.height() - 3, _pExpandMarkWidth * 2, 3), 2, 2);
// 展开图标绘制
QRect expandIconRect = subControlRect(QStyle::CC_ComboBox, copt, QStyle::SC_ScrollBarAddPage, widget);
if (expandIconRect.isValid())
{
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->setPen(isEnabled ? ElaThemeColor(_themeMode, BasicText) : ElaThemeColor(_themeMode, BasicTextDisable));
painter->translate(expandIconRect.x() + (qreal)expandIconRect.width() / 2, expandIconRect.y() + (qreal)expandIconRect.height() / 2);
painter->rotate(_pExpandIconRotate);
painter->translate(-expandIconRect.x() - (qreal)expandIconRect.width() / 2, -expandIconRect.y() - (qreal)expandIconRect.height() / 2);
painter->drawText(expandIconRect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::AngleDown));
painter->restore();
}
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
QRect ElaComboBoxStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const
{
switch (cc)
{
case QStyle::CC_ComboBox:
{
switch (sc)
{
case QStyle::SC_ScrollBarSubLine:
{
//文字区域
QRect textRect = QProxyStyle::subControlRect(cc, opt, sc, widget);
textRect.setLeft(16);
textRect.setRight(textRect.right() - 15);
return textRect;
}
case QStyle::SC_ScrollBarAddPage:
{
//展开图标区域
QRect expandIconRect = QProxyStyle::subControlRect(cc, opt, sc, widget);
expandIconRect.setLeft(expandIconRect.left() - 25);
return expandIconRect;
}
default:
{
break;
}
}
break;
}
default:
{
break;
}
}
return QProxyStyle::subControlRect(cc, opt, sc, widget);
}
QSize ElaComboBoxStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
switch (type)
{
case QStyle::CT_ItemViewItem:
{
QSize itemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
itemSize.setHeight(35);
return itemSize;
}
case QStyle::CT_ComboBox:
{
QSize comboBoxSize = QProxyStyle::sizeFromContents(type, option, size, widget);
comboBoxSize.setWidth(comboBoxSize.width() + 26);
return comboBoxSize;
}
default:
{
break;
}
}
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
@@ -0,0 +1,27 @@
#ifndef ELACOMBOBOXSTYLE_H
#define ELACOMBOBOXSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaComboBoxStyle : public QProxyStyle
{
Q_OBJECT
Q_PROPERTY_CREATE(qreal, ExpandIconRotate)
Q_PROPERTY_CREATE(qreal, ExpandMarkWidth)
public:
explicit ElaComboBoxStyle(QStyle* style = nullptr);
~ElaComboBoxStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
private:
ElaThemeType::ThemeMode _themeMode;
int _shadowBorderWidth{6};
};
#endif // ELACOMBOBOXSTYLE_H
@@ -0,0 +1,22 @@
#include "ElaComboBoxView.h"
#include <QMouseEvent>
ElaComboBoxView::ElaComboBoxView(QWidget* parent)
: QListView(parent)
{
}
ElaComboBoxView::~ElaComboBoxView()
{
}
void ElaComboBoxView::mousePressEvent(QMouseEvent* event)
{
QModelIndex index = indexAt(event->pos());
if (index.isValid())
{
Q_EMIT itemPressed(index);
}
event->ignore();
}
@@ -0,0 +1,19 @@
#ifndef ELACOMBOBOXVIEW_H
#define ELACOMBOBOXVIEW_H
#include <QListView>
class ElaComboBoxView : public QListView
{
Q_OBJECT
public:
explicit ElaComboBoxView(QWidget* parent = nullptr);
~ElaComboBoxView();
Q_SIGNALS:
Q_SIGNAL void itemPressed(const QModelIndex& index);
protected:
void mousePressEvent(QMouseEvent* event) override;
};
#endif // ELACOMBOBOXVIEW_H
@@ -0,0 +1,77 @@
#include "ElaCustomTabWidget.h"
#include <QVBoxLayout>
#include <QVariant>
#include "ElaAppBar.h"
#include "ElaTabBar.h"
#include "ElaTabWidget.h"
#include "ElaTabWidgetPrivate.h"
ElaCustomTabWidget::ElaCustomTabWidget(QWidget* parent)
: ElaCustomWidget(parent)
{
resize(700, 500);
setWindowTitle("");
setWindowIcon(QIcon());
_customTabWidget = new ElaTabWidget(this);
QTabBar* originTabBar = _customTabWidget->tabBar();
originTabBar->hide();
_customTabBar = new ElaTabBar(this);
_customTabBar->setObjectName("ElaCustomTabBar");
connect(_customTabBar, &ElaTabBar::tabMoved, this, [=](int from, int to) {
_customTabWidget->tabBar()->moveTab(from, to);
});
connect(_customTabBar, &ElaTabBar::currentChanged, this, [=](int index) {
_customTabWidget->setCurrentIndex(index);
});
connect(_customTabWidget, &ElaTabWidget::currentChanged, this, [=](int index) {
if (index == -1)
{
close();
}
});
connect(_customTabBar, &ElaTabBar::tabCloseRequested, originTabBar, &QTabBar::tabCloseRequested);
QWidget* customWidget = new QWidget(this);
QVBoxLayout* customLayout = new QVBoxLayout(customWidget);
customLayout->setContentsMargins(10, 0, 10, 0);
customLayout->addStretch();
customLayout->addWidget(_customTabBar);
_appBar->setCustomWidget(ElaAppBarType::LeftArea, customWidget);
setCentralWidget(_customTabWidget);
}
ElaCustomTabWidget::~ElaCustomTabWidget()
{
while (_customTabWidget->count() > 0)
{
QWidget* closeWidget = _customTabWidget->widget(0);
ElaTabWidget* originTabWidget = closeWidget->property("ElaOriginTabWidget").value<ElaTabWidget*>();
if (originTabWidget)
{
closeWidget->setProperty("CurrentCustomBar", QVariant::fromValue<ElaTabBar*>(nullptr));
originTabWidget->addTab(closeWidget, _customTabWidget->tabIcon(0), _customTabWidget->tabText(0));
}
else
{
_customTabWidget->removeTab(0);
}
}
}
void ElaCustomTabWidget::addTab(QWidget* widget, QIcon& tabIcon, const QString& tabTitle)
{
_customTabBar->addTab(tabIcon, tabTitle);
_customTabWidget->addTab(widget, tabIcon, tabTitle);
}
ElaTabBar* ElaCustomTabWidget::getCustomTabBar() const
{
return _customTabBar;
}
ElaTabWidget* ElaCustomTabWidget::getCustomTabWidget() const
{
return _customTabWidget;
}
@@ -0,0 +1,23 @@
#ifndef ELACUSTOMTABWIDGET_H
#define ELACUSTOMTABWIDGET_H
#include "ElaCustomWidget.h"
class ElaTabBar;
class ElaTabWidget;
class ElaCustomTabWidget : public ElaCustomWidget
{
Q_OBJECT
public:
explicit ElaCustomTabWidget(QWidget* parent = nullptr);
~ElaCustomTabWidget();
void addTab(QWidget* widget, QIcon& tabIcon, const QString& tabTitle);
ElaTabBar* getCustomTabBar() const;
ElaTabWidget* getCustomTabWidget() const;
private:
ElaTabBar* _customTabBar{nullptr};
ElaTabWidget* _customTabWidget{nullptr};
};
#endif // ELACUSTOMTABWIDGET_H
@@ -0,0 +1,62 @@
#include "ElaCustomWidget.h"
#include <QPainter>
#include <QVBoxLayout>
#include "ElaApplication.h"
#include "ElaTheme.h"
Q_TAKEOVER_NATIVEEVENT_CPP(ElaCustomWidget, _appBar);
ElaCustomWidget::ElaCustomWidget(QWidget* parent)
: QDialog{parent}
{
resize(500, 500); // 默认宽高
setObjectName("ElaCustomWidget");
// 自定义AppBar
_appBar = new ElaAppBar(this);
_appBar->setWindowButtonFlags(ElaAppBarType::MinimizeButtonHint | ElaAppBarType::MaximizeButtonHint | ElaAppBarType::CloseButtonHint);
_mainLayout = new QVBoxLayout(this);
_mainLayout->setContentsMargins(0, 0, 0, 0);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
update();
});
_isEnableMica = eApp->getIsEnableMica();
connect(eApp, &ElaApplication::pIsEnableMicaChanged, this, [=]() {
_isEnableMica = eApp->getIsEnableMica();
update();
});
eApp->syncMica(this);
setAttribute(Qt::WA_DeleteOnClose);
}
ElaCustomWidget::~ElaCustomWidget()
{
}
void ElaCustomWidget::setCentralWidget(QWidget* widget)
{
if (!widget)
{
return;
}
_centralWidget = widget;
_mainLayout->addWidget(widget);
widget->setVisible(true);
}
void ElaCustomWidget::paintEvent(QPaintEvent* event)
{
if (!_isEnableMica)
{
QPainter painter(this);
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(ElaThemeColor(_themeMode, WindowBase));
painter.drawRect(rect());
painter.restore();
}
}
@@ -0,0 +1,31 @@
#ifndef ELACUSTOMWIDGET_H
#define ELACUSTOMWIDGET_H
#include <QDialog>
#include "Def.h"
#include "ElaAppBar.h"
class QVBoxLayout;
class ElaCustomWidget : public QDialog
{
Q_OBJECT
Q_TAKEOVER_NATIVEEVENT_H
public:
explicit ElaCustomWidget(QWidget* parent = nullptr);
~ElaCustomWidget();
void setCentralWidget(QWidget* widget);
protected:
virtual void paintEvent(QPaintEvent* event) override;
QVBoxLayout* _mainLayout{nullptr};
ElaAppBar* _appBar{nullptr};
QWidget* _centralWidget{nullptr};
private:
ElaThemeType::ThemeMode _themeMode;
bool _isEnableMica;
};
#endif // ELACUSTOMWIDGET_H
@@ -0,0 +1,88 @@
#include "ElaDockWidgetTitleBar.h"
#include <QHBoxLayout>
#include <QPainter>
#include "ElaDockWidget.h"
#include "ElaIconButton.h"
#include "ElaText.h"
#include "ElaTheme.h"
ElaDockWidgetTitleBar::ElaDockWidgetTitleBar(QWidget* parent)
: QWidget{parent}
{
_dockWidget = dynamic_cast<ElaDockWidget*>(parent);
_iconLabel = new QLabel(this);
_iconLabel->setPixmap(_dockWidget->windowIcon().pixmap(QSize(18, 18)));
_titleLabel = new ElaText(_dockWidget->windowTitle(), this);
_titleLabel->setWordWrap(false);
_titleLabel->setTextPixelSize(13);
_floatButton = new ElaIconButton(ElaIconType::WindowRestore, 13, 32, 26, this);
_floatButton->setLightHoverColor(ElaThemeColor(ElaThemeType::Light, BasicHoverAlpha));
_floatButton->setDarkHoverColor(ElaThemeColor(ElaThemeType::Dark, BasicHoverAlpha));
connect(_floatButton, &ElaIconButton::clicked, this, &ElaDockWidgetTitleBar::onFloatButtonClicked);
_closeButton = new ElaIconButton(ElaIconType::Xmark, 17, 32, 26, this);
_closeButton->setLightHoverColor(ElaThemeColor(ElaThemeType::Light, StatusDanger));
_closeButton->setDarkHoverColor(ElaThemeColor(ElaThemeType::Dark, StatusDanger));
connect(_closeButton, &ElaIconButton::clicked, this, &ElaDockWidgetTitleBar::onCloseButtonClicked);
_setVisibleFromFeatures(_dockWidget->features());
connect(_dockWidget, &QDockWidget::featuresChanged, this, [=](QDockWidget::DockWidgetFeatures features) {
_setVisibleFromFeatures(features);
});
connect(_dockWidget, &QDockWidget::windowTitleChanged, this, [=](const QString& title) {
_titleLabel->setText(title);
});
connect(_dockWidget, &QDockWidget::windowIconChanged, this, [=](const QIcon& icon) {
_iconLabel->setPixmap(icon.pixmap(QSize(18, 18)));
});
QHBoxLayout* mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addSpacing(5);
mainLayout->addWidget(_iconLabel);
mainLayout->addSpacing(10);
mainLayout->addWidget(_titleLabel);
mainLayout->addSpacing(10);
mainLayout->addStretch();
mainLayout->addWidget(_floatButton);
mainLayout->addWidget(_closeButton);
//主题变更
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaDockWidgetTitleBar::~ElaDockWidgetTitleBar()
{
}
void ElaDockWidgetTitleBar::onFloatButtonClicked()
{
_dockWidget->setFloating(_dockWidget->isFloating() ? false : true);
}
void ElaDockWidgetTitleBar::onCloseButtonClicked()
{
_dockWidget->close();
}
void ElaDockWidgetTitleBar::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(_dockWidget->isFloating() ? Qt::transparent : ElaThemeColor(_themeMode, BasicBaseAlpha));
painter.drawRect(rect());
painter.restore();
}
void ElaDockWidgetTitleBar::_setVisibleFromFeatures(QDockWidget::DockWidgetFeatures features)
{
_floatButton->setVisible(features.testFlag(QDockWidget::DockWidgetFloatable));
_closeButton->setVisible(features.testFlag(QDockWidget::DockWidgetClosable));
}
@@ -0,0 +1,36 @@
#ifndef ELADOCKWIDGETTITLEBAR_H
#define ELADOCKWIDGETTITLEBAR_H
#include <QDockWidget>
#include <QLabel>
#include <QWidget>
#include "Def.h"
class ElaText;
class ElaIconButton;
class ElaDockWidget;
class ElaDockWidgetTitleBar : public QWidget
{
Q_OBJECT
public:
explicit ElaDockWidgetTitleBar(QWidget* parent = nullptr);
~ElaDockWidgetTitleBar();
Q_SLOT void onFloatButtonClicked();
Q_SLOT void onCloseButtonClicked();
protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
friend class ElaDockWidgetPrivate;
ElaThemeType::ThemeMode _themeMode;
ElaDockWidget* _dockWidget{nullptr};
QLabel* _iconLabel{nullptr};
ElaText* _titleLabel{nullptr};
ElaIconButton* _floatButton{nullptr};
ElaIconButton* _closeButton{nullptr};
void _setVisibleFromFeatures(QDockWidget::DockWidgetFeatures features);
};
#endif // ELADOCKWIDGETTITLEBAR_H
@@ -0,0 +1,322 @@
#include "ElaDxgi.h"
#ifdef Q_OS_WIN
#include <QDateTime>
#include <QDebug>
ElaDxgi::ElaDxgi(QObject* parent)
: QObject(parent)
{
_pIsInitSuccess = false;
_pIsGrabActive = false;
_pGrabFrameRate = 120;
_pTimeoutMsValue = 50;
_pIsGrabStoped = true;
_pIsGrabCenter = false;
}
ElaDxgi::~ElaDxgi()
{
releaseInterface();
}
bool ElaDxgi::initialize(int dxID, int outputID)
{
_pIsInitSuccess = false;
_pDxDeviceID = dxID;
_pOutputDeviceID = outputID;
releaseInterface();
ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dContext = nullptr;
D3D_FEATURE_LEVEL feat = D3D_FEATURE_LEVEL_11_0;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
D3D11_SDK_VERSION, &d3dDevice, &feat, &d3dContext);
if (FAILED(hr))
{
_pLastError = "Failed to D3D11CreateDevice ErrorCode = " + QString::number(uint(hr), 16);
qDebug() << _pLastError;
if (d3dDevice)
{
d3dDevice->Release();
}
if (d3dContext)
{
d3dContext->Release();
}
return false;
}
IDXGIFactory* dxgiFactory = nullptr;
CreateDXGIFactory(__uuidof(dxgiFactory), reinterpret_cast<void**>(&dxgiFactory));
IDXGIAdapter* dxgiAdapter = nullptr;
QVector<IDXGIAdapter*> dxgiAdapterVector;
for (uint i = 0; dxgiFactory->EnumAdapters(i, &dxgiAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
{
dxgiAdapterVector.append(dxgiAdapter);
}
dxgiFactory->Release();
dxgiAdapter = nullptr;
_pDxDeviceList.clear();
for (int i = 0; i < dxgiAdapterVector.count(); i++)
{
IDXGIAdapter* adapt = dxgiAdapterVector.at(i);
DXGI_ADAPTER_DESC desc;
adapt->GetDesc(&desc);
_pDxDeviceList.append(QString::fromWCharArray(desc.Description));
}
if (dxID >= 0 && dxID < dxgiAdapterVector.count())
{
dxgiAdapter = dxgiAdapterVector.at(dxID);
}
if (!dxgiAdapter)
{
_pLastError = "Failed to found gpu";
qDebug() << _pLastError;
d3dDevice->Release();
d3dContext->Release();
for (auto adapter: dxgiAdapterVector)
{
adapter->Release();
}
return false;
}
IDXGIOutput* dxgiOutput = nullptr;
QVector<IDXGIOutput*> dxgiOutputVector;
for (uint i = 0; dxgiAdapter->EnumOutputs(i, &dxgiOutput) != DXGI_ERROR_NOT_FOUND; ++i)
{
dxgiOutputVector.append(dxgiOutput);
}
for (auto adapter: dxgiAdapterVector)
{
adapter->Release();
}
dxgiOutput = nullptr;
_pOutputDeviceList.clear();
for (int i = 0; i < dxgiOutputVector.count(); i++)
{
const auto& output = dxgiOutputVector.at(i);
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
_pOutputDeviceList.append(QString::fromWCharArray(desc.DeviceName));
}
if (outputID >= 0 && outputID < dxgiOutputVector.count())
{
dxgiOutput = dxgiOutputVector.at(outputID);
}
if (!dxgiOutput)
{
_pLastError = "Failed to found screen!";
qDebug() << _pLastError;
d3dDevice->Release();
d3dContext->Release();
for (auto output: dxgiOutputVector)
{
output->Release();
}
return false;
}
IDXGIOutput6* dxgiOutput6 = nullptr;
hr = dxgiOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void**>(&dxgiOutput6));
for (auto output: dxgiOutputVector)
{
output->Release();
}
if (FAILED(hr))
{
_pLastError = "Failed to QueryInterface IDXGIOutput6 ErrorCode = " + QString::number(uint(hr), 16);
qDebug() << _pLastError;
d3dDevice->Release();
d3dContext->Release();
dxgiOutput6->Release();
return false;
}
UINT supportedFormatsCount = 1; // 支持的格式数
DXGI_FORMAT supportedFormats[1] = {DXGI_FORMAT_B8G8R8A8_UNORM};
hr = dxgiOutput6->DuplicateOutput1(d3dDevice, 0, supportedFormatsCount, supportedFormats, &_duplication);
dxgiOutput6->Release();
if (FAILED(hr))
{
_pLastError = "Failed to DuplicateOutput ErrorCode = " + QString::number(uint(hr), 16);
qDebug() << _pLastError;
d3dDevice->Release();
d3dContext->Release();
if (_duplication)
{
_duplication->Release();
_duplication = nullptr;
}
return false;
}
_device = d3dDevice;
_context = d3dContext;
_pIsInitSuccess = true;
return true;
}
QImage ElaDxgi::getGrabImage() const
{
QImage grabImage(_imageBits, _descWidth, _descHeight, QImage::Format_ARGB32);
if (_pIsGrabCenter)
{
return grabImage.copy(QRect((_descWidth - _pGrabArea.width()) / 2, (_descHeight - _pGrabArea.height()) / 2, _pGrabArea.width(), _pGrabArea.height()));
}
else
{
return grabImage.copy(_pGrabArea);
}
}
void ElaDxgi::onGrabScreen()
{
qreal startTime = 0;
qreal endTime = 0;
if (!_duplication || !_device || !_context)
{
setIsGrabStoped(true);
return;
}
_pIsGrabStoped = false;
while (_pIsGrabActive)
{
IDXGIResource* desktopRes = nullptr;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
while (true)
{
if (!_pIsGrabActive)
{
setIsGrabStoped(true);
return;
}
startTime = QDateTime::currentMSecsSinceEpoch();
_duplication->ReleaseFrame();
HRESULT hr = _duplication->AcquireNextFrame(_pTimeoutMsValue, &frameInfo, &desktopRes);
if (FAILED(hr))
{
if (hr != DXGI_ERROR_WAIT_TIMEOUT)
{
if (desktopRes)
{
desktopRes->Release();
desktopRes = nullptr;
}
while (true)
{
if (!_duplication || !_device || !_context)
{
setIsGrabStoped(true);
return;
}
if (initialize(_pDxDeviceID, _pOutputDeviceID))
{
break;
}
}
}
continue;
}
if (frameInfo.LastPresentTime.QuadPart)
{
break;
}
}
D3D11_TEXTURE2D_DESC desc;
ID3D11Texture2D* textrueRes = nullptr;
HRESULT hr = desktopRes->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&textrueRes));
desktopRes->Release();
if (FAILED(hr))
{
qDebug() << "Failed to ID3D11Texture2D result =" << QString::number(uint(hr), 16);
continue;
}
textrueRes->GetDesc(&desc);
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));
texDesc.Width = desc.Width;
texDesc.Height = desc.Height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_STAGING;
texDesc.Format = desc.Format;
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
_device->CreateTexture2D(&texDesc, nullptr, &_texture);
_context->CopyResource(_texture, textrueRes);
IDXGISurface1* surface = nullptr;
hr = _texture->QueryInterface(__uuidof(IDXGISurface1), reinterpret_cast<void**>(&surface));
if (FAILED(hr))
{
qDebug() << "Failed to QueryInterface IDXGISurface1 ErrorCode ="
<< QString::number(uint(hr), 16);
continue;
}
DXGI_MAPPED_RECT map;
surface->Map(&map, DXGI_MAP_READ);
_imageBits = static_cast<uchar*>(map.pBits);
_descWidth = desc.Width;
_descHeight = desc.Height;
surface->Unmap();
surface->Release();
_texture->Release();
Q_EMIT grabScreenOver();
endTime = QDateTime::currentMSecsSinceEpoch();
if (_lastGrabTime == 0)
{
_lastGrabTime = endTime - startTime; // 毫秒
}
else
{
_lastGrabTime = ((endTime - startTime) + _lastGrabTime) / 2.0;
}
_cpuSleepTime = (1000 - _lastGrabTime * _pGrabFrameRate) / _pGrabFrameRate;
cpuSleep(_cpuSleepTime * 1000);
// qDebug() << _cpuSleepTime << _lastGrabTime;
}
setIsGrabStoped(true);
}
void ElaDxgi::releaseInterface()
{
if (_duplication)
{
_duplication->Release();
_duplication = nullptr;
}
if (_device)
{
_device->Release();
_device = nullptr;
}
if (_context)
{
_context->Release();
_context = nullptr;
}
}
void ElaDxgi::cpuSleep(int usec)
{
if (usec <= 0)
{
return;
}
LARGE_INTEGER cpuFerq;
LARGE_INTEGER startTime;
LARGE_INTEGER endTime;
QueryPerformanceFrequency(&cpuFerq);
QueryPerformanceCounter(&startTime);
while (1)
{
QueryPerformanceCounter(&endTime);
if (((endTime.QuadPart - startTime.QuadPart) * 1000000) / cpuFerq.QuadPart > usec)
{
break;
}
}
}
#endif
@@ -0,0 +1,51 @@
#ifndef ELADXGI_H
#define ELADXGI_H
#include <QObject>
#ifdef Q_OS_WIN
#include <d3d11.h>
#include <dxgi1_6.h>
#include <QPixmap>
#include "stdafx.h"
class ElaDxgi : public QObject
{
Q_OBJECT
Q_PRIVATE_CREATE(QStringList, DxDeviceList)
Q_PRIVATE_CREATE(QStringList, OutputDeviceList)
Q_PRIVATE_CREATE(int, DxDeviceID);
Q_PRIVATE_CREATE(int, OutputDeviceID);
Q_PRIVATE_CREATE(QString, LastError)
Q_PRIVATE_CREATE(bool, IsGrabActive)
Q_PRIVATE_CREATE(QRect, GrabArea);
Q_PRIVATE_CREATE(int, GrabFrameRate); // 截图帧数
Q_PRIVATE_CREATE(int, TimeoutMsValue); // 超时等待
Q_PRIVATE_CREATE(bool, IsInitSuccess);
Q_PRIVATE_CREATE(bool, IsGrabStoped);
Q_PRIVATE_CREATE(bool, IsGrabCenter);
public:
explicit ElaDxgi(QObject* parent = nullptr);
~ElaDxgi();
bool initialize(int dxID, int outputID);
QImage getGrabImage() const;
Q_SLOT void onGrabScreen();
Q_SIGNAL void grabScreenOver();
private:
IDXGIOutputDuplication* _duplication{nullptr};
ID3D11Device* _device{nullptr};
ID3D11DeviceContext* _context{nullptr};
ID3D11Texture2D* _texture{nullptr};
qreal _lastGrabTime{0};
qreal _cpuSleepTime{0};
uchar* _imageBits{nullptr};
int _descWidth{0};
int _descHeight{0};
void releaseInterface();
void cpuSleep(int usec);
};
#endif
#endif // ELADXGI_H
@@ -0,0 +1,266 @@
#include "ElaFooterDelegate.h"
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include "ElaBaseListView.h"
#include "ElaFooterModel.h"
#include "ElaNavigationNode.h"
#include "ElaTheme.h"
ElaFooterDelegate::ElaFooterDelegate(QObject* parent)
: QStyledItemDelegate{parent}
{
_pElaListView = nullptr;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
setProperty("lastSelectMarkTop", 10.0);
setProperty("lastSelectMarkBottom", 10.0);
setProperty("selectMarkTop", 10.0);
setProperty("selectMarkBottom", 10.0);
// Mark向上
_lastSelectMarkTopAnimation = new QPropertyAnimation(this, "lastSelectMarkTop");
connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_lastSelectMarkTop = value.toReal();
_pElaListView->viewport()->update(); });
_lastSelectMarkTopAnimation->setDuration(300);
_lastSelectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);
_selectMarkBottomAnimation = new QPropertyAnimation(this, "selectMarkBottom");
connect(_selectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_selectMarkBottom = value.toReal();
_pElaListView->viewport()->update(); });
_selectMarkBottomAnimation->setDuration(300);
_selectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);
connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::finished, this, [=]() {
_isSelectMarkDisplay = true;
_lastSelectedNode = nullptr;
_selectMarkBottomAnimation->setStartValue(0);
_selectMarkBottomAnimation->setEndValue(10);
_selectMarkBottomAnimation->start(); });
// Mark向下
_lastSelectMarkBottomAnimation = new QPropertyAnimation(this, "lastSelectMarkBottom");
connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_lastSelectMarkBottom = value.toReal();
_pElaListView->viewport()->update(); });
_lastSelectMarkBottomAnimation->setDuration(300);
_lastSelectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);
_selectMarkTopAnimation = new QPropertyAnimation(this, "selectMarkTop");
connect(_selectMarkTopAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_selectMarkTop = value.toReal();
_pElaListView->viewport()->update(); });
_selectMarkTopAnimation->setDuration(300);
_selectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);
connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::finished, this, [=]() {
_isSelectMarkDisplay = true;
_lastSelectedNode = nullptr;
_selectMarkTopAnimation->setStartValue(0);
_selectMarkTopAnimation->setEndValue(10);
_selectMarkTopAnimation->start(); });
}
ElaFooterDelegate::~ElaFooterDelegate()
{
}
void ElaFooterDelegate::navigationNodeStateChange(QVariantMap data)
{
if (data.contains("SelectMarkChanged"))
{
_lastSelectedNode = data.value("LastSelectedNode").value<ElaNavigationNode*>();
ElaNavigationNode* selectedNode = data.value("SelectedNode").value<ElaNavigationNode*>();
bool direction = _compareItemY(selectedNode, _lastSelectedNode);
_lastSelectMarkTop = 10;
_lastSelectMarkBottom = 10;
_selectMarkTop = 10;
_selectMarkBottom = 10;
if (direction)
{
_lastSelectMarkTopAnimation->setStartValue(10);
_lastSelectMarkTopAnimation->setEndValue(0);
_lastSelectMarkTopAnimation->start();
_lastSelectMarkBottomAnimation->stop();
_selectMarkTopAnimation->stop();
_isSelectMarkDisplay = false;
}
else
{
_lastSelectMarkBottomAnimation->setStartValue(10);
_lastSelectMarkBottomAnimation->setEndValue(0);
_lastSelectMarkBottomAnimation->start();
_lastSelectMarkTopAnimation->stop();
_selectMarkBottomAnimation->stop();
_isSelectMarkDisplay = false;
}
}
}
void ElaFooterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
ElaFooterModel* model = dynamic_cast<ElaFooterModel*>(const_cast<QAbstractItemModel*>(index.model()));
ElaNavigationNode* node = index.data(Qt::UserRole).value<ElaNavigationNode*>();
if (option.state.testFlag(QStyle::State_HasFocus))
{
viewOption.state &= ~QStyle::State_HasFocus;
}
QStyledItemDelegate::paint(painter, viewOption, index);
// 背景绘制
QRect itemRect = option.rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
itemRect.setTop(itemRect.top() + 2);
itemRect.setBottom(itemRect.bottom() - 2);
QPainterPath path;
path.addRoundedRect(itemRect, 8, 8);
if (option.state & QStyle::State_Selected)
{
if (index == _pPressIndex)
{
// 选中时点击
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
else
{
if (option.state & QStyle::State_MouseOver)
{
// 选中时覆盖
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
// 选中
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedAlpha));
}
}
}
else
{
if (index == _pPressIndex)
{
// 点击时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
if (option.state & QStyle::State_MouseOver)
{
// 覆盖时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
}
}
painter->restore();
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
itemRect = option.rect;
//顶边线绘制
if (index.row() == 0)
{
painter->setPen(ElaThemeColor(_themeMode, BasicBaseLine));
painter->drawLine(option.rect.x(), itemRect.y() + 1, option.rect.x() + option.rect.width(), itemRect.y() + 1);
}
// 图标绘制
painter->setPen(index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
if (node->getAwesome() != ElaIconType::None)
{
painter->save();
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->drawText(QRect(itemRect.x(), itemRect.y(), _iconAreaWidth, itemRect.height()), Qt::AlignCenter, QChar((unsigned short)node->getAwesome()));
painter->restore();
}
int keyPoints = node->getKeyPoints();
if (keyPoints)
{
// KeyPoints
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::white);
painter->drawEllipse(QPoint(255, itemRect.y() + itemRect.height() / 2), 10, 10);
painter->setBrush(ElaThemeColor(_themeMode, StatusDanger));
painter->drawEllipse(QPoint(255, itemRect.y() + itemRect.height() / 2), 9, 9);
painter->setPen(QPen(Qt::white, 2));
QFont font = painter->font();
font.setBold(true);
if (keyPoints > 99)
{
keyPoints = 99;
}
if (keyPoints > 9)
{
font.setPixelSize(11);
}
else
{
font.setPixelSize(12);
}
painter->setFont(font);
painter->drawText(keyPoints > 9 ? 248 : 251, itemRect.y() + itemRect.height() / 2 + 4, QString::number(keyPoints));
painter->restore();
}
// 文字绘制
painter->setPen(index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
QRect textRect;
if (node->getAwesome() != ElaIconType::None)
{
textRect = QRect(itemRect.x() + _iconAreaWidth, itemRect.y(), itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _iconAreaWidth, itemRect.height());
}
else
{
textRect = QRect(itemRect.x() + _leftPadding, itemRect.y(), itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _leftPadding, itemRect.height());
}
QString text = painter->fontMetrics().elidedText(node->getNodeTitle(), Qt::ElideRight, textRect.width());
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
// 选中特效
if (_isSelectMarkDisplay && (node == model->getSelectedNode()))
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(itemRect.x() + 3, itemRect.y() + _selectMarkTop, 3, itemRect.height() - _selectMarkTop - _selectMarkBottom), 3, 3);
}
if (node == _lastSelectedNode)
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(itemRect.x() + 3, itemRect.y() + _lastSelectMarkTop, 3, itemRect.height() - _lastSelectMarkTop - _lastSelectMarkBottom), 3, 3);
}
painter->restore();
}
QSize ElaFooterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(40);
return size;
}
bool ElaFooterDelegate::_compareItemY(ElaNavigationNode* node1, ElaNavigationNode* node2)
{
if (!node1)
{
return true;
}
if (!node2)
{
return false;
}
if (node1->getModelIndex().row() < node2->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
@@ -0,0 +1,45 @@
#ifndef ELAFOOTERDELEGATE_H
#define ELAFOOTERDELEGATE_H
#include <QModelIndex>
#include <QStyledItemDelegate>
#include "Def.h"
class ElaNavigationNode;
class QPropertyAnimation;
class ElaBaseListView;
class ElaFooterDelegate : public QStyledItemDelegate
{
Q_OBJECT
Q_PRIVATE_CREATE(ElaBaseListView*, ElaListView);
Q_PRIVATE_CREATE(QModelIndex, PressIndex);
public:
explicit ElaFooterDelegate(QObject* parent = nullptr);
~ElaFooterDelegate();
void navigationNodeStateChange(QVariantMap data);
protected:
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
int _leftPadding{11};
int _iconAreaWidth{40};
int _textRightSpacing{3};
int _indicatorIconAreaWidth{24};
qreal _lastSelectMarkTop{10};
qreal _lastSelectMarkBottom{10};
qreal _selectMarkTop{10};
qreal _selectMarkBottom{10};
bool _isSelectMarkDisplay{true};
ElaNavigationNode* _lastSelectedNode{nullptr};
ElaThemeType::ThemeMode _themeMode;
QPropertyAnimation* _lastSelectMarkTopAnimation{nullptr};
QPropertyAnimation* _lastSelectMarkBottomAnimation{nullptr};
QPropertyAnimation* _selectMarkTopAnimation{nullptr};
QPropertyAnimation* _selectMarkBottomAnimation{nullptr};
bool _compareItemY(ElaNavigationNode* node1, ElaNavigationNode* node2);
};
#endif // ELAFOOTERDELEGATE_H
@@ -0,0 +1,68 @@
#include "ElaFooterModel.h"
#include <QUuid>
#include "ElaNavigationNode.h"
ElaFooterModel::ElaFooterModel(QObject* parent)
: QAbstractListModel{parent}
{
_pSelectedNode = nullptr;
}
ElaFooterModel::~ElaFooterModel()
{
qDeleteAll(_footerNodeList);
}
int ElaFooterModel::rowCount(const QModelIndex& parent) const
{
return _footerNodeList.count();
}
QVariant ElaFooterModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::UserRole)
{
if (index.row() < _footerNodeList.count())
{
return QVariant::fromValue(_footerNodeList[index.row()]);
}
}
return QVariant();
}
ElaNavigationType::NodeOperateReturnType ElaFooterModel::addFooterNode(QString footerTitle, QString& footerKey, bool isHasFooterPage, int keyPoints, ElaIconType::IconName awesome)
{
if (_footerNodeList.count() >= 3)
{
return ElaNavigationType::FooterUpperLimit;
}
ElaNavigationNode* node = new ElaNavigationNode(footerTitle);
node->setKeyPoints(keyPoints);
node->setIsFooterNode(true);
node->setIsHasFooterPage(isHasFooterPage);
node->setAwesome(awesome);
footerKey = node->getNodeKey();
beginResetModel();
_footerNodeList.append(node);
endResetModel();
node->setModelIndex(this->index(_footerNodeList.count() - 1));
return ElaNavigationType::Success;
}
int ElaFooterModel::getFooterNodeCount() const
{
return _footerNodeList.count();
}
ElaNavigationNode* ElaFooterModel::getNavigationNode(QString footerKey)
{
for (auto node : _footerNodeList)
{
if (node->getNodeKey() == footerKey)
{
return node;
}
}
return nullptr;
}
@@ -0,0 +1,28 @@
#ifndef ELAFOOTERMODEL_H
#define ELAFOOTERMODEL_H
#include <QAbstractListModel>
#include "Def.h"
#include "stdafx.h"
class ElaNavigationNode;
class ElaFooterModel : public QAbstractListModel
{
Q_OBJECT
Q_PRIVATE_CREATE(ElaNavigationNode*, SelectedNode)
public:
explicit ElaFooterModel(QObject* parent = nullptr);
~ElaFooterModel();
ElaNavigationType::NodeOperateReturnType addFooterNode(QString footerTitle, QString& footerKey, bool isHasFooterPage, int keyPoints = 0, ElaIconType::IconName awesome = ElaIconType::None);
int getFooterNodeCount() const;
ElaNavigationNode* getNavigationNode(QString footerKey);
protected:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
private:
QList<ElaNavigationNode*> _footerNodeList;
};
#endif // ELAFOOTERMODEL_H
@@ -0,0 +1,86 @@
#include "ElaIntValidator.h"
ElaIntValidator::ElaIntValidator(QObject* parent)
: QIntValidator{parent}
{
_pIsHexMode = false;
}
ElaIntValidator::ElaIntValidator(int bottom, int top, QObject* parent)
: QIntValidator{bottom, top, parent}
{
_pIsHexMode = false;
}
ElaIntValidator::~ElaIntValidator()
{
}
QValidator::State ElaIntValidator::validate(QString& input, int& pos) const
{
QString inputCopy = input;
if (_pIsHexMode)
{
inputCopy.remove("#");
if (!inputCopy.isEmpty())
{
bool isInt = false;
int value = inputCopy.toInt(&isInt, 16);
if (!isInt)
{
return QValidator::Invalid;
}
if (value < bottom() || value > top())
{
return QValidator::Invalid;
}
int topLength = QString::number(top(), 16).length();
if (inputCopy.length() > topLength)
{
return QValidator::Invalid;
}
}
inputCopy.prepend("#");
}
else
{
if (input.isEmpty())
{
return QValidator::Intermediate;
}
bool isInt = false;
int value = inputCopy.toInt(&isInt);
if (!isInt)
{
return QValidator::Invalid;
}
if (value < bottom() || value > top())
{
return QValidator::Invalid;
}
}
input = inputCopy;
return QValidator::Acceptable;
}
void ElaIntValidator::fixup(QString& input) const
{
if (_pIsHexMode)
{
QString inputComplete = _completeInput(input, QString::number(top(), 16).length());
input = QString("#") + inputComplete;
}
else
{
input = QString::number(bottom());
}
}
QString ElaIntValidator::_completeInput(QString input, int length) const
{
while (input.length() < length)
{
input.prepend("0");
}
return input;
}
@@ -0,0 +1,23 @@
#ifndef ELAINTVALIDATOR_H
#define ELAINTVALIDATOR_H
#include <QIntValidator>
#include "stdafx.h"
class ElaIntValidator : public QIntValidator
{
Q_OBJECT
Q_PRIVATE_CREATE(bool, IsHexMode)
public:
explicit ElaIntValidator(QObject* parent = nullptr);
explicit ElaIntValidator(int bottom, int top, QObject* parent = nullptr);
~ElaIntValidator();
QValidator::State validate(QString& input, int& pos) const override;
void fixup(QString& input) const override;
private:
QString _completeInput(QString input, int length) const;
};
#endif // ELAINTVALIDATOR_H
@@ -0,0 +1,144 @@
#include "ElaKeyBinderContainer.h"
#include "ElaKeyBinder.h"
#include "ElaTheme.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QtMath>
ElaKeyBinderContainer::ElaKeyBinderContainer(QWidget* parent)
: QWidget(parent)
{
_keyBinder = dynamic_cast<ElaKeyBinder*>(parent);
setStyleSheet("#ElaKeyBinderContainer{background-color:transparent;}");
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
setFixedHeight(140);
QFont textFont = font();
textFont.setLetterSpacing(QFont::AbsoluteSpacing, 0.5);
textFont.setPixelSize(16);
setFont(textFont);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaKeyBinderContainer::~ElaKeyBinderContainer()
{
}
void ElaKeyBinderContainer::logOrResetHistoryData(bool isLog)
{
if (isLog)
{
_historyBinderKeyText = _pBinderKeyText;
_historyNativeVirtualBinderKey = _pNativeVirtualBinderKey;
}
else
{
_pBinderKeyText = _historyBinderKeyText;
_pNativeVirtualBinderKey = _historyNativeVirtualBinderKey;
update();
}
}
void ElaKeyBinderContainer::saveBinderChanged()
{
Q_EMIT _keyBinder->binderKeyTextChanged(_pBinderKeyText);
Q_EMIT _keyBinder->nativeVirtualBinderKeyChanged(_pNativeVirtualBinderKey);
if (_pBinderKeyText.isEmpty())
{
_keyBinder->setText(u8" 按键: " + QString(u8"未绑定") + " ");
}
else
{
_keyBinder->setText(u8" 按键: " + _pBinderKeyText + " ");
}
}
void ElaKeyBinderContainer::mousePressEvent(QMouseEvent* event)
{
switch (event->button())
{
case Qt::LeftButton:
{
_pBinderKeyText = "Mouse1";
_pNativeVirtualBinderKey = 0x01;
break;
}
case Qt::RightButton:
{
_pBinderKeyText = "Mouse2";
_pNativeVirtualBinderKey = 0x02;
break;
}
case Qt::MiddleButton:
{
_pBinderKeyText = "Middle";
_pNativeVirtualBinderKey = 0x04;
break;
}
case Qt::BackButton:
{
_pBinderKeyText = "Back";
_pNativeVirtualBinderKey = 0x05;
break;
}
case Qt::ForwardButton:
{
_pBinderKeyText = "Forward";
_pNativeVirtualBinderKey = 0x06;
break;
}
default:
{
break;
}
}
QWidget::mousePressEvent(event);
update();
}
void ElaKeyBinderContainer::keyPressEvent(QKeyEvent* event)
{
if (!event->isAutoRepeat())
{
_pBinderKeyText = QKeySequence(event->key()).toString();
_pNativeVirtualBinderKey = event->nativeVirtualKey();
update();
}
QWidget::keyPressEvent(event);
}
void ElaKeyBinderContainer::focusOutEvent(QFocusEvent* event)
{
QWidget::focusOutEvent(event);
setFocus();
}
void ElaKeyBinderContainer::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
// 顶部提示绘制
painter.setPen(ElaThemeColor(_themeMode, BasicText));
painter.drawText(QRect(20, 20, width(), 50), Qt::AlignLeft | Qt::AlignTop, u8"按下任意按键以进行绑定");
if (_pBinderKeyText.isEmpty())
{
painter.restore();
return;
}
// 中心文字背景绘制
painter.setPen(ElaThemeColor(_themeMode, BasicBorder));
painter.setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
qreal textWidth = fontMetrics().horizontalAdvance(_pBinderKeyText) * 1.3;
qreal textHeight = fontMetrics().height() * 1.2;
textWidth = qMax(textWidth, 35.0);
textHeight = qMax(textHeight, 35.0);
painter.drawRoundedRect(QRectF((width() - textWidth) / 2.0, rect().center().y() + 10, textWidth, textHeight), 5, 5);
// 文字绘制
painter.setPen(ElaThemeColor(_themeMode, BasicTextInvert));
painter.drawText(QRectF((width() - textWidth) / 2.0, rect().center().y() + 10, textWidth, textHeight), Qt::AlignCenter, _pBinderKeyText);
painter.restore();
}
@@ -0,0 +1,31 @@
#ifndef ELAWIDGETTOOLS_SRC_DEVELOPERCOMPONENTS_ELAKEYBINDERCONTAINER_H_
#define ELAWIDGETTOOLS_SRC_DEVELOPERCOMPONENTS_ELAKEYBINDERCONTAINER_H_
#include "Def.h"
#include <QWidget>
class ElaKeyBinder;
class ElaKeyBinderContainer : public QWidget
{
Q_OBJECT
Q_PRIVATE_CREATE(QString, BinderKeyText)
Q_PRIVATE_CREATE(quint32, NativeVirtualBinderKey)
public:
explicit ElaKeyBinderContainer(QWidget* parent = nullptr);
~ElaKeyBinderContainer();
void logOrResetHistoryData(bool isLog);
void saveBinderChanged();
protected:
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void keyPressEvent(QKeyEvent* event) override;
virtual void focusOutEvent(QFocusEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
private:
QString _historyBinderKeyText;
quint32 _historyNativeVirtualBinderKey{0};
ElaThemeType::ThemeMode _themeMode;
ElaKeyBinder* _keyBinder{nullptr};
};
#endif//ELAWIDGETTOOLS_SRC_DEVELOPERCOMPONENTS_ELAKEYBINDERCONTAINER_H_
@@ -0,0 +1,52 @@
#include "ElaLCDNumberStyle.h"
#include "ElaTheme.h"
#include <QDebug>
#include <QPainter>
#include <QStyleOption>
ElaLCDNumberStyle::ElaLCDNumberStyle(QStyle* style)
{
_pIsTransparent = false;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaLCDNumberStyle::~ElaLCDNumberStyle()
{
}
void ElaLCDNumberStyle::drawControl(QStyle::ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ShapedFrame:
{
if (const QStyleOptionFrame* fopt = qstyleoption_cast<const QStyleOptionFrame*>(option))
{
if (!_pIsTransparent)
{
// 背景绘制
QRect numberRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
// 边框绘制
painter->setBrush(ElaThemeColor(_themeMode, BasicBorder));
painter->drawRoundedRect(numberRect, 6, 6);
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawRoundedRect(QRectF(numberRect.x() + 1.5, numberRect.y() + 1.5, numberRect.width() - 3, numberRect.height() - 3), 6, 6);
painter->restore();
}
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
@@ -0,0 +1,19 @@
#ifndef ELAWIDGETTOOLS_ELALCDNUMBERSTYLE_H
#define ELAWIDGETTOOLS_ELALCDNUMBERSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaLCDNumberStyle : public QProxyStyle
{
Q_OBJECT
Q_PRIVATE_CREATE(bool, IsTransparent)
public:
explicit ElaLCDNumberStyle(QStyle* style = nullptr);
~ElaLCDNumberStyle();
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif //ELAWIDGETTOOLS_ELALCDNUMBERSTYLE_H
@@ -0,0 +1,69 @@
#include "ElaLineEditStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include <QtMath>
#include "ElaTheme.h"
ElaLineEditStyle::ElaLineEditStyle(QStyle* style)
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaLineEditStyle::~ElaLineEditStyle()
{
}
void ElaLineEditStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case PE_PanelLineEdit:
{
if (const QStyleOptionFrame* fopt = qstyleoption_cast<const QStyleOptionFrame*>(option))
{
QRect lineEditRect = fopt->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
// 边框绘制
painter->setBrush(ElaThemeColor(_themeMode, BasicBorder));
painter->drawRoundedRect(lineEditRect, 6, 6);
// 背景绘制
if (fopt->state & QStyle::State_HasFocus)
{
painter->setBrush(ElaThemeColor(_themeMode, DialogBase));
}
else if (fopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHover));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
}
painter->drawRoundedRect(QRectF(lineEditRect.x() + 1.5, lineEditRect.y() + 1.5, lineEditRect.width() - 3, lineEditRect.height() - 3), 6, 6);
// 底边线绘制
painter->setBrush(ElaThemeColor(_themeMode, BasicHemline));
QPainterPath path;
path.moveTo(6, lineEditRect.height());
path.lineTo(lineEditRect.width() - 6, lineEditRect.height());
path.arcTo(QRectF(lineEditRect.width() - 12, lineEditRect.height() - 12, 12, 12), -90, 45);
path.lineTo(6 - 3 * std::sqrt(2), lineEditRect.height() - (6 - 3 * std::sqrt(2)));
path.arcTo(QRectF(0, lineEditRect.height() - 12, 12, 12), 270, 45);
path.closeSubpath();
painter->drawPath(path);
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
@@ -0,0 +1,19 @@
#ifndef ELALINEEDITSTYLE_H
#define ELALINEEDITSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaLineEditStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaLineEditStyle(QStyle* style = nullptr);
~ElaLineEditStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELALINEEDITSTYLE_H
@@ -0,0 +1,194 @@
#include "ElaListViewStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaListView.h"
#include "ElaTheme.h"
ElaListViewStyle::ElaListViewStyle(QStyle* style)
{
_pItemHeight = 35;
_pIsTransparent = false;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaListViewStyle::~ElaListViewStyle()
{
}
void ElaListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelItemViewItem:
{
// Item背景
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
QRect itemRect = vopt->rect;
itemRect.adjust(0, 2, 0, -2);
QPainterPath path;
path.addRoundedRect(itemRect, 4, 4);
if (vopt->state & QStyle::State_Selected)
{
if (vopt->state & QStyle::State_MouseOver)
{
// 选中时覆盖
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
// 选中
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedAlpha));
}
}
else
{
if (vopt->state & QStyle::State_MouseOver)
{
// 覆盖时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
}
painter->restore();
}
return;
}
case QStyle::PE_PanelItemViewRow:
{
// Item背景隔行变色
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
if (vopt->features == QStyleOptionViewItem::Alternate)
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicAlternating));
painter->drawRect(vopt->rect);
painter->restore();
}
}
return;
}
case QStyle::PE_Widget:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaListViewStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ShapedFrame:
{
// viewport视口外的其他区域背景
if (!_pIsTransparent)
{
QRect frameRect = option->rect;
frameRect.adjust(1, 1, -1, -1);
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(ElaThemeColor(_themeMode, PopupBorder));
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawRoundedRect(frameRect, 3, 3);
painter->restore();
}
return;
}
case QStyle::CE_ItemViewItem:
{
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
// 背景绘制
this->drawPrimitive(QStyle::PE_PanelItemViewItem, option, painter, widget);
// 内容绘制
QRect itemRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
const ElaListView* listView = dynamic_cast<const ElaListView*>(widget);
QListView::ViewMode viewMode = listView->viewMode();
// QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
iconRect.adjust(_leftPadding, 0, 0, 0);
textRect.adjust(_leftPadding, 0, 0, 0);
// 图标绘制
if (!vopt->icon.isNull())
{
QIcon::Mode mode = QIcon::Normal;
if (!(vopt->state.testFlag(QStyle::State_Enabled)))
{
mode = QIcon::Disabled;
}
else if (vopt->state.testFlag(QStyle::State_Selected))
{
mode = QIcon::Selected;
}
QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
}
// 文字绘制
if (!vopt->text.isEmpty())
{
painter->setPen(ElaThemeColor(_themeMode, BasicText));
painter->drawText(textRect, vopt->displayAlignment, vopt->text);
}
// 选中特效
if (vopt->state.testFlag(QStyle::State_Selected) && viewMode == QListView::ListMode)
{
int heightOffset = itemRect.height() / 4;
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(itemRect.x() + 3, itemRect.y() + heightOffset, 3, itemRect.height() - 2 * heightOffset), 3, 3);
}
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QSize ElaListViewStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
switch (type)
{
case QStyle::CT_ItemViewItem:
{
QSize itemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
const ElaListView* listView = dynamic_cast<const ElaListView*>(widget);
QListView::ViewMode viewMode = listView->viewMode();
if (viewMode == QListView::ListMode)
{
itemSize.setWidth(itemSize.width() + _leftPadding);
}
itemSize.setHeight(_pItemHeight);
return itemSize;
}
default:
{
break;
}
}
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
@@ -0,0 +1,24 @@
#ifndef ELALISTVIEWSTYLE_H
#define ELALISTVIEWSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaListViewStyle : public QProxyStyle
{
Q_OBJECT
Q_PROPERTY_CREATE(int, ItemHeight)
Q_PROPERTY_CREATE(bool, IsTransparent)
public:
explicit ElaListViewStyle(QStyle* style = nullptr);
~ElaListViewStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
private:
ElaThemeType::ThemeMode _themeMode;
int _leftPadding{11};
};
#endif // ELALISTVIEWSTYLE_H
@@ -0,0 +1,45 @@
#include "ElaMaskWidget.h"
#include <QPainter>
#include <QPropertyAnimation>
ElaMaskWidget::ElaMaskWidget(QWidget* parent)
: QWidget{parent}
{
setObjectName("ElaMaskWidget");
setStyleSheet("#ElaMaskWidget{background-color:transparent;}");
_pMaskAlpha = 0;
}
ElaMaskWidget::~ElaMaskWidget()
{
}
void ElaMaskWidget::doMaskAnimation(int endValue)
{
QPropertyAnimation* opacityAnimation = new QPropertyAnimation(this, "pMaskAlpha");
connect(opacityAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
update();
});
connect(opacityAnimation, &QPropertyAnimation::finished, this, [=]() {
if (endValue == 0)
{
setVisible(false);
}
});
opacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
opacityAnimation->setDuration(250);
opacityAnimation->setStartValue(_pMaskAlpha);
opacityAnimation->setEndValue(endValue);
opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
void ElaMaskWidget::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setPen(Qt::NoPen);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(QColor(0x00, 0x00, 0x00, _pMaskAlpha));
painter.drawRect(rect());
painter.restore();
}
@@ -0,0 +1,20 @@
#ifndef ELAMASKWIDGET_H
#define ELAMASKWIDGET_H
#include <QWidget>
#include "stdafx.h"
class ElaMaskWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY_CREATE(int, MaskAlpha)
public:
explicit ElaMaskWidget(QWidget* parent = nullptr);
~ElaMaskWidget();
void doMaskAnimation(int endValue);
protected:
virtual void paintEvent(QPaintEvent* event) override;
};
#endif // ELAMASKWIDGET_H
@@ -0,0 +1,225 @@
#include "ElaMenuBarStyle.h"
#include <QDebug>
#include <QPainter>
#include <QStyleOption>
#include "ElaMenuBar.h"
#include "ElaTheme.h"
ElaMenuBarStyle::ElaMenuBarStyle(QStyle* style)
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaMenuBarStyle::~ElaMenuBarStyle()
{
}
void ElaMenuBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelButtonTool:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaMenuBarStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ToolButtonLabel:
{
if (const QStyleOptionToolButton* topt = qstyleoption_cast<const QStyleOptionToolButton*>(option))
{
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter->setPen(Qt::NoPen);
if (topt->state.testFlag(QStyle::State_Enabled) && topt->state.testFlag(QStyle::State_MouseOver))
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHoverAlpha));
painter->drawRect(topt->rect);
}
//展开图标
painter->setPen(!topt->state.testFlag(QStyle::State_Enabled) ? Qt::gray : ElaThemeColor(_themeMode, BasicText));
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(18);
painter->setFont(iconFont);
painter->drawText(topt->rect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::AngleRight));
painter->restore();
}
return;
}
case QStyle::CE_MenuBarEmptyArea:
{
return;
}
case QStyle::CE_MenuBarItem:
{
if (const QStyleOptionMenuItem* mopt = qstyleoption_cast<const QStyleOptionMenuItem*>(option))
{
if (mopt->menuItemType == QStyleOptionMenuItem::Separator)
{
return;
}
int menuBarHeight = widget->height();
QRect menuItemRect = mopt->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
//背景绘制
painter->setPen(Qt::NoPen);
if (mopt->state.testFlag(QStyle::State_Enabled))
{
if (mopt->state.testFlag(QStyle::State_Sunken))
{
painter->setBrush(ElaThemeColor(_themeMode, BasicPressAlpha));
}
else if (mopt->state.testFlag(QStyle::State_Selected))
{
painter->setBrush(ElaThemeColor(_themeMode, BasicSelectedAlpha));
}
painter->drawRoundedRect(menuItemRect, 3, 3);
}
//图标和文字绘制
QIcon icon = mopt->icon;
QString menuText = mopt->text;
QString iconText;
menuText = menuText.replace("&", "");
const ElaMenuBar* menuBar = dynamic_cast<const ElaMenuBar*>(widget);
if (menuBar)
{
QAction* action = menuBar->actionAt(menuItemRect.center());
if (action)
{
iconText = action->property("ElaIconType").toString();
}
}
if (menuText.isEmpty())
{
//图标
if (!iconText.isEmpty())
{
painter->save();
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? ElaThemeColor(_themeMode, BasicTextDisable) : ElaThemeColor(_themeMode, BasicText));
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(menuBarHeight * 0.7);
painter->setFont(iconFont);
painter->drawText(menuItemRect, Qt::AlignCenter, iconText);
painter->restore();
}
else if (!icon.isNull())
{
QRect menuIconRect(menuItemRect.center().x() - menuBarHeight * 0.4, menuItemRect.center().y() - menuBarHeight * 0.4, menuBarHeight * 0.8, menuBarHeight * 0.8);
painter->drawPixmap(menuIconRect, icon.pixmap(menuBarHeight * 0.8, menuBarHeight * 0.8));
}
}
else
{
//图标 + 文字
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? ElaThemeColor(_themeMode, BasicTextDisable) : ElaThemeColor(_themeMode, BasicText));
if (icon.isNull() && iconText.isEmpty())
{
painter->drawText(menuItemRect, Qt::AlignCenter, menuText);
}
else
{
if (!iconText.isEmpty())
{
QRectF menuIconRect(menuItemRect.x() + menuBarHeight * 0.1 + _menuBarItemMargin, menuBarHeight * 0.1, menuBarHeight * 0.8, menuBarHeight * 0.8);
painter->save();
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(menuBarHeight * 0.7);
painter->setFont(iconFont);
painter->drawText(menuIconRect, Qt::AlignCenter, iconText);
painter->restore();
painter->drawText(QRect(menuIconRect.right(), menuItemRect.y(), menuItemRect.width() - menuIconRect.width(), menuBarHeight), Qt::AlignCenter, menuText);
}
else
{
QRect menuIconRect(menuItemRect.x() + menuBarHeight * 0.1 + _menuBarItemMargin, menuBarHeight * 0.1, menuBarHeight * 0.8, menuBarHeight * 0.8);
painter->drawPixmap(menuIconRect, icon.pixmap(menuBarHeight * 0.8, menuBarHeight * 0.8));
painter->drawText(QRect(menuIconRect.right(), menuItemRect.y(), menuItemRect.width() - menuIconRect.width(), menuBarHeight), Qt::AlignCenter, menuText);
}
}
}
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QSize ElaMenuBarStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
switch (type)
{
case QStyle::CT_MenuBar:
{
QSize menuBarHeight = QProxyStyle::sizeFromContents(type, option, size, widget);
menuBarHeight.setHeight(widget->height());
return menuBarHeight;
}
case QStyle::CT_MenuBarItem:
{
if (const QStyleOptionMenuItem* mopt = qstyleoption_cast<const QStyleOptionMenuItem*>(option))
{
QSize menuBarItemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
menuBarItemSize.setHeight(widget->height());
if ((!mopt->icon.isNull()) && !mopt->text.isEmpty())
{
menuBarItemSize.setWidth(menuBarItemSize.width() + mopt->fontMetrics.horizontalAdvance(mopt->text) + 2 * _menuBarItemMargin);
}
if (!mopt->text.contains("&"))
{
menuBarItemSize.setWidth(menuBarItemSize.width() + 5);
}
return menuBarItemSize;
}
}
default:
{
break;
}
}
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
int ElaMenuBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_MenuBarHMargin:
{
return 0;
}
case QStyle::PM_MenuBarItemSpacing:
{
return 6;
}
case QStyle::PM_ToolBarExtensionExtent:
{
return 26;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
@@ -0,0 +1,23 @@
#ifndef ELAMENUBARSTYLE_H
#define ELAMENUBARSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaMenuBarStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaMenuBarStyle(QStyle* style = nullptr);
~ElaMenuBarStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
int _menuBarItemMargin{0};
};
#endif // ELAMENUBARSTYLE_H
@@ -0,0 +1,233 @@
#include "ElaMenuStyle.h"
#include <QDebug>
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaMenu.h"
#include "ElaTheme.h"
ElaMenuStyle::ElaMenuStyle(QStyle* style)
{
_pMenuItemHeight = 32;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaMenuStyle::~ElaMenuStyle()
{
}
void ElaMenuStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelMenu:
{
// 高性能阴影
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
eTheme->drawEffectShadow(painter, option->rect, _shadowBorderWidth, 6);
// 背景绘制
QRect foregroundRect(_shadowBorderWidth, _shadowBorderWidth, option->rect.width() - 2 * _shadowBorderWidth, option->rect.height() - 2 * _shadowBorderWidth);
painter->setPen(ElaThemeColor(_themeMode, PopupBorder));
painter->setBrush(ElaThemeColor(_themeMode, PopupBase));
painter->drawRoundedRect(foregroundRect, 6, 6);
painter->restore();
return;
}
case QStyle::PE_FrameMenu:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaMenuStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_MenuItem:
{
//内容绘制 区分类型
if (const QStyleOptionMenuItem* mopt = qstyleoption_cast<const QStyleOptionMenuItem*>(option))
{
if (mopt->menuItemType == QStyleOptionMenuItem::Separator)
{
QRect separatorRect = mopt->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseLine));
painter->drawRoundedRect(QRectF(separatorRect.x() + separatorRect.width() * 0.055, separatorRect.center().y(), separatorRect.width() - separatorRect.width() * 0.11, 1.5), 1, 1);
painter->restore();
return;
}
else
{
QRect menuRect = mopt->rect;
qreal contentPadding = menuRect.width() * 0.055;
qreal textLeftSpacing = menuRect.width() * 0.082;
painter->save();
painter->setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing);
//覆盖效果
if (mopt->state.testFlag(QStyle::State_Enabled) && (mopt->state.testFlag(QStyle::State_MouseOver) || mopt->state.testFlag(QStyle::State_Selected)))
{
QRect hoverRect = menuRect;
hoverRect.adjust(0, 2, 0, -2);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PopupHover));
painter->drawRoundedRect(hoverRect, 5, 5);
}
//Icon绘制
QIcon menuIcon = mopt->icon;
//check绘制
if (mopt->menuHasCheckableItems)
{
painter->save();
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? Qt::gray : _themeMode == ElaThemeType::Light ? Qt::black
: Qt::white);
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(_pMenuItemHeight * 0.57);
painter->setFont(iconFont);
painter->drawText(QRectF(menuRect.x() + contentPadding, menuRect.y(), _iconWidth, menuRect.height()), Qt::AlignCenter, mopt->checked ? QChar((unsigned short)ElaIconType::Check) : QChar((unsigned short)ElaIconType::None));
painter->restore();
}
else
{
QString iconText;
const ElaMenu* menu = dynamic_cast<const ElaMenu*>(widget);
if (menu)
{
QAction* action = menu->actionAt(menuRect.center());
if (action)
{
iconText = action->property("ElaIconType").toString();
}
}
if (!iconText.isEmpty())
{
painter->save();
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? Qt::gray : _themeMode == ElaThemeType::Light ? Qt::black
: Qt::white);
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(_pMenuItemHeight * 0.57);
painter->setFont(iconFont);
painter->drawText(QRectF(menuRect.x() + contentPadding, menuRect.y(), _iconWidth, menuRect.height()), Qt::AlignCenter, iconText);
painter->restore();
}
else
{
if (!menuIcon.isNull())
{
painter->drawPixmap(QRect(menuRect.x() + contentPadding, menuRect.center().y() - _iconWidth / 2, _iconWidth, _iconWidth), menuIcon.pixmap(_iconWidth, _iconWidth));
}
}
}
//文字和快捷键绘制
if (!mopt->text.isEmpty())
{
QStringList textList = mopt->text.split("\t");
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? Qt::gray : _themeMode == ElaThemeType::Light ? Qt::black
: Qt::white);
painter->drawText(QRectF(menuRect.x() + (_isAnyoneItemHasIcon ? contentPadding + textLeftSpacing : 0) + _iconWidth, menuRect.y(), menuRect.width(), menuRect.height()), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, textList[0]);
if (textList.count() > 1)
{
painter->drawText(QRectF(menuRect.x() + contentPadding + _iconWidth + textLeftSpacing, menuRect.y(), menuRect.width() - (contentPadding * 2 + _iconWidth + textLeftSpacing), menuRect.height()), Qt::AlignRight | Qt::AlignVCenter | Qt::TextSingleLine, textList[1]);
}
}
//展开图标
if (mopt->menuItemType == QStyleOptionMenuItem::SubMenu)
{
painter->save();
painter->setPen(!mopt->state.testFlag(QStyle::State_Enabled) ? Qt::gray : _themeMode == ElaThemeType::Light ? Qt::black
: Qt::white);
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(18);
painter->setFont(iconFont);
painter->drawText(QRect(menuRect.right() - 25, menuRect.y(), 25, menuRect.height()), Qt::AlignVCenter, QChar((unsigned short)ElaIconType::AngleRight));
painter->restore();
}
painter->restore();
}
}
return;
}
case QStyle::CE_MenuEmptyArea:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
int ElaMenuStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_SmallIconSize:
{
//图标宽度
return _iconWidth;
}
case QStyle::PM_MenuPanelWidth:
{
//外围容器宽度
return _shadowBorderWidth * 1.5;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
QSize ElaMenuStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
switch (type)
{
case QStyle::CT_MenuItem:
{
if (const QStyleOptionMenuItem* mopt = qstyleoption_cast<const QStyleOptionMenuItem*>(option))
{
if (mopt->menuItemType == QStyleOptionMenuItem::Separator)
{
break;
}
QSize menuItemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
const ElaMenu* menu = dynamic_cast<const ElaMenu*>(widget);
if (menu->isHasIcon() || mopt->menuHasCheckableItems)
{
_isAnyoneItemHasIcon = true;
}
if (menu->isHasChildMenu())
{
return QSize(menuItemSize.width() + 20, _pMenuItemHeight);
}
else
{
return QSize(menuItemSize.width(), _pMenuItemHeight);
}
}
}
default:
{
break;
}
}
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
@@ -0,0 +1,28 @@
#ifndef ELAMENUSTYLE_H
#define ELAMENUSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaMenuStyle : public QProxyStyle
{
Q_OBJECT
Q_PROPERTY_CREATE(int, MenuItemHeight);
public:
explicit ElaMenuStyle(QStyle* style = nullptr);
~ElaMenuStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
private:
mutable bool _isAnyoneItemHasIcon{false};
int _shadowBorderWidth{6};
ElaThemeType::ThemeMode _themeMode;
int _iconWidth{22};
};
#endif // ELAMENUSTYLE_H
@@ -0,0 +1,71 @@
#include "ElaMicaBaseInitObject.h"
#include <QImage>
#include "ElaApplicationPrivate.h"
#include "ElaExponentialBlur.h"
ElaMicaBaseInitObject::ElaMicaBaseInitObject(ElaApplicationPrivate* appPrivate, QObject* parent)
: QObject{parent}
{
_appPrivate = appPrivate;
}
ElaMicaBaseInitObject::~ElaMicaBaseInitObject()
{
}
void ElaMicaBaseInitObject::onInitMicaBase(QImage img)
{
// QColorDialog
// 统一处理为1920*1080以节省空间
img = img.scaled(QSize(1920, 1080), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
QImage blurImage = ElaExponentialBlur::doExponentialBlur(img, 500).toImage();
QImage lightImage = blurImage;
QImage darkImage = blurImage;
QColor lightMixColor = QColor(0xF3, 0xF3, 0xF3);
lightMixColor = lightMixColor.toHsv();
QColor darkMixColor = QColor(0x20, 0x20, 0x20);
darkMixColor = darkMixColor.toHsv();
QColor originColor;
QColor lightColor;
QColor darkColor;
int h, s, v;
for (int y = 0; y < blurImage.height(); y++)
{
QRgb* line = (QRgb*)blurImage.scanLine(y);
for (int x = 0; x < blurImage.width(); x++)
{
originColor = QColor(line[x]);
originColor = originColor.toHsv();
h = originColor.hsvHue();
s = originColor.hsvSaturation();
v = originColor.value();
if (s / 20 > 11)
{
lightColor.setHsv(h, (s / 20 + 11) / 2, 250);
}
else
{
lightColor.setHsv(h, 11, 250);
}
lightColor = lightColor.toRgb();
if (v / 1.1 > 40)
{
darkColor.setHsv(h, s / 2, (v / 1.1 + 40) / 2);
}
else
{
darkColor.setHsv(h, s / 2, 40);
}
darkColor = darkColor.toRgb();
lightImage.setPixel(x, y, qRgb(lightColor.red(), lightColor.green(), lightColor.blue()));
darkImage.setPixel(x, y, qRgb(darkColor.red(), darkColor.green(), darkColor.blue()));
}
}
_appPrivate->_lightBaseImage = lightImage.copy();
_appPrivate->_darkBaseImage = darkImage.copy();
// _appPrivate->_lightBaseImage.save("light.png", "PNG");
// _appPrivate->_darkBaseImage.save("dark.png", "PNG");
Q_EMIT initFinished();
}
@@ -0,0 +1,20 @@
#ifndef ELAMICABASEINITOBJECT_H
#define ELAMICABASEINITOBJECT_H
#include <QObject>
class ElaApplicationPrivate;
class ElaMicaBaseInitObject : public QObject
{
Q_OBJECT
public:
explicit ElaMicaBaseInitObject(ElaApplicationPrivate* appPrivate, QObject* parent = nullptr);
~ElaMicaBaseInitObject();
Q_SLOT void onInitMicaBase(QImage img);
Q_SIGNALS:
Q_SIGNAL void initFinished();
private:
ElaApplicationPrivate* _appPrivate{nullptr};
};
#endif // ELAMICABASEINITOBJECT_H
@@ -0,0 +1,284 @@
#include "ElaNavigationModel.h"
#include <QIcon>
#include <QJsonObject>
#include "ElaNavigationNode.h"
ElaNavigationModel::ElaNavigationModel(QObject* parent)
: QAbstractItemModel{parent}
{
_rootNode = new ElaNavigationNode("root");
_rootNode->setIsRootNode(true);
_rootNode->setIsExpanderNode(true);
_pSelectedNode = nullptr;
_pSelectedExpandedNode = nullptr;
}
ElaNavigationModel::~ElaNavigationModel()
{
delete _rootNode;
}
QModelIndex ElaNavigationModel::parent(const QModelIndex& child) const
{
if (!child.isValid())
{
return QModelIndex();
}
ElaNavigationNode* childNode = static_cast<ElaNavigationNode*>(child.internalPointer());
ElaNavigationNode* parentNode = childNode->getParentNode();
if (parentNode == _rootNode)
{
return QModelIndex();
}
else if (parentNode == nullptr)
{
return QModelIndex();
}
return createIndex(parentNode->getRow(), 0, parentNode);
}
QModelIndex ElaNavigationModel::index(int row, int column, const QModelIndex& parent) const
{
if (!hasIndex(row, column, parent))
{
return QModelIndex();
}
ElaNavigationNode* parentNode;
if (!parent.isValid())
{
parentNode = _rootNode;
}
else
{
parentNode = static_cast<ElaNavigationNode*>(parent.internalPointer());
}
ElaNavigationNode* childNode = nullptr;
if (parentNode->getChildrenNodes().count() > row)
{
childNode = parentNode->getChildrenNodes().at(row);
}
if (childNode)
{
return createIndex(row, column, childNode);
}
return QModelIndex();
}
int ElaNavigationModel::rowCount(const QModelIndex& parent) const
{
ElaNavigationNode* parentNode;
if (parent.column() > 0)
{
return 0;
}
if (!parent.isValid())
{
parentNode = _rootNode;
}
else
{
parentNode = static_cast<ElaNavigationNode*>(parent.internalPointer());
}
return parentNode->getChildrenNodes().count();
};
int ElaNavigationModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant ElaNavigationModel::data(const QModelIndex& index, int role) const
{
Q_UNUSED(index)
Q_UNUSED(role)
return QVariant();
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addExpanderNode(QString expanderTitle, QString& expanderKey, ElaIconType::IconName awesome)
{
ElaNavigationNode* node = new ElaNavigationNode(expanderTitle, _rootNode);
node->setDepth(1);
node->setIsVisible(true);
node->setIsExpanderNode(true);
node->setAwesome(awesome);
beginInsertRows(QModelIndex(), _rootNode->getChildrenNodes().count(), _rootNode->getChildrenNodes().count());
_rootNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
expanderKey = node->getNodeKey();
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addExpanderNode(QString expanderTitle, QString& expanderKey, QString targetExpanderKey, ElaIconType::IconName awesome)
{
if (!_nodesMap.contains(targetExpanderKey))
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeInvalid;
}
ElaNavigationNode* parentNode = _nodesMap.value(targetExpanderKey);
if (!parentNode->getIsExpanderNode())
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeTypeError;
}
if (parentNode->getDepth() > 10)
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeDepthLimit;
}
ElaNavigationNode* node = new ElaNavigationNode(expanderTitle, parentNode);
node->setDepth(parentNode->getDepth() + 1);
node->setIsExpanderNode(true);
node->setAwesome(awesome);
if (parentNode->getIsVisible() && parentNode->getIsExpanded())
{
node->setIsVisible(true);
}
beginInsertRows(parentNode->getModelIndex(), parentNode->getChildrenNodes().count(), parentNode->getChildrenNodes().count());
parentNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
expanderKey = node->getNodeKey();
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addPageNode(QString pageTitle, QString& pageKey, ElaIconType::IconName awesome)
{
ElaNavigationNode* node = new ElaNavigationNode(pageTitle, _rootNode);
node->setAwesome(awesome);
node->setDepth(1);
node->setIsVisible(true);
beginInsertRows(QModelIndex(), _rootNode->getChildrenNodes().count(), _rootNode->getChildrenNodes().count());
_rootNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
pageKey = node->getNodeKey();
if (!_pSelectedNode)
{
_pSelectedNode = node;
}
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addPageNode(QString pageTitle, QString& pageKey, QString targetExpanderKey, ElaIconType::IconName awesome)
{
if (!_nodesMap.contains(targetExpanderKey))
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeInvalid;
}
ElaNavigationNode* parentNode = _nodesMap.value(targetExpanderKey);
if (!parentNode->getIsExpanderNode())
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeTypeError;
}
if (parentNode->getDepth() > 10)
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeDepthLimit;
}
ElaNavigationNode* node = new ElaNavigationNode(pageTitle, parentNode);
node->setDepth(parentNode->getDepth() + 1);
node->setAwesome(awesome);
if (parentNode->getIsVisible() && parentNode->getIsExpanded())
{
node->setIsVisible(true);
}
beginInsertRows(parentNode->getModelIndex(), parentNode->getChildrenNodes().count(), parentNode->getChildrenNodes().count());
parentNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
pageKey = node->getNodeKey();
if (!_pSelectedNode)
{
_pSelectedNode = node;
}
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addPageNode(QString pageTitle, QString& pageKey, int keyPoints, ElaIconType::IconName awesome)
{
ElaNavigationNode* node = new ElaNavigationNode(pageTitle, _rootNode);
node->setAwesome(awesome);
node->setDepth(1);
node->setIsVisible(true);
node->setKeyPoints(keyPoints);
beginInsertRows(QModelIndex(), _rootNode->getChildrenNodes().count(), _rootNode->getChildrenNodes().count());
_rootNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
pageKey = node->getNodeKey();
if (!_pSelectedNode)
{
_pSelectedNode = node;
}
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationType::NodeOperateReturnType ElaNavigationModel::addPageNode(QString pageTitle, QString& pageKey, QString targetExpanderKey, int keyPoints, ElaIconType::IconName awesome)
{
if (!_nodesMap.contains(targetExpanderKey))
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeInvalid;
}
ElaNavigationNode* parentNode = _nodesMap.value(targetExpanderKey);
if (!parentNode->getIsExpanderNode())
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeTypeError;
}
if (parentNode->getDepth() > 10)
{
return ElaNavigationType::NodeOperateReturnType::TargetNodeDepthLimit;
}
ElaNavigationNode* node = new ElaNavigationNode(pageTitle, parentNode);
node->setDepth(parentNode->getDepth() + 1);
node->setAwesome(awesome);
node->setKeyPoints(keyPoints);
if (parentNode->getIsVisible() && parentNode->getIsExpanded())
{
node->setIsVisible(true);
}
beginInsertRows(parentNode->getModelIndex(), parentNode->getChildrenNodes().count(), parentNode->getChildrenNodes().count());
parentNode->appendChildNode(node);
_nodesMap.insert(node->getNodeKey(), node);
endInsertRows();
pageKey = node->getNodeKey();
if (!_pSelectedNode)
{
_pSelectedNode = node;
}
return ElaNavigationType::NodeOperateReturnType::Success;
}
ElaNavigationNode* ElaNavigationModel::getNavigationNode(QString nodeKey) const
{
if (_nodesMap.contains(nodeKey))
{
return _nodesMap.value(nodeKey);
}
return nullptr;
}
QList<ElaNavigationNode*> ElaNavigationModel::getRootExpanderNodes() const
{
QList<ElaNavigationNode*> expandedNodeList;
for (auto node : _rootNode->getChildrenNodes())
{
if (node->getIsExpanderNode())
{
expandedNodeList.append(node);
}
}
return expandedNodeList;
}
QList<ElaNavigationNode*> ElaNavigationModel::getRootExpandedNodes() const
{
QList<ElaNavigationNode*> expandedNodeList;
for (auto node : _rootNode->getChildrenNodes())
{
if (node->getIsExpanderNode() && node->getIsExpanded())
{
expandedNodeList.append(node);
}
}
return expandedNodeList;
}
@@ -0,0 +1,40 @@
#ifndef ELANAVIGATIONMODEL_H
#define ELANAVIGATIONMODEL_H
#include <QAbstractItemModel>
#include <QObject>
#include "Def.h"
#include "stdafx.h"
class ElaNavigationNode;
class ElaNavigationModel : public QAbstractItemModel
{
Q_OBJECT
Q_PRIVATE_CREATE(ElaNavigationNode*, SelectedNode)
Q_PRIVATE_CREATE(ElaNavigationNode*, SelectedExpandedNode)
public:
explicit ElaNavigationModel(QObject* parent = nullptr);
~ElaNavigationModel();
QModelIndex parent(const QModelIndex& child) const override;
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
ElaNavigationType::NodeOperateReturnType addExpanderNode(QString expanderTitle, QString& expanderKey, ElaIconType::IconName awesome);
ElaNavigationType::NodeOperateReturnType addExpanderNode(QString expanderTitle, QString& expanderKey, QString targetExpanderKey, ElaIconType::IconName awesome);
ElaNavigationType::NodeOperateReturnType addPageNode(QString pageTitle, QString& pageKey, ElaIconType::IconName awesome);
ElaNavigationType::NodeOperateReturnType addPageNode(QString pageTitle, QString& pageKey, QString targetExpanderKey, ElaIconType::IconName awesome);
ElaNavigationType::NodeOperateReturnType addPageNode(QString pageTitle, QString& pageKey, int keyPoints, ElaIconType::IconName awesome);
ElaNavigationType::NodeOperateReturnType addPageNode(QString pageTitle, QString& pageKey, QString targetExpanderKey, int keyPoints, ElaIconType::IconName awesome);
ElaNavigationNode* getNavigationNode(QString nodeKey) const;
QList<ElaNavigationNode*> getRootExpanderNodes() const;
QList<ElaNavigationNode*> getRootExpandedNodes() const;
private:
mutable QMap<QString, ElaNavigationNode*> _nodesMap;
ElaNavigationNode* _rootNode{nullptr};
};
#endif // ELANAVIGATIONMODEL_H
@@ -0,0 +1,166 @@
#include "ElaNavigationNode.h"
#include <QUuid>
ElaNavigationNode::ElaNavigationNode(QString nodeTitle, ElaNavigationNode* parent)
: QObject(parent)
{
_pDepth = 0;
_pKeyPoints = 0;
_nodeKey = QUuid::createUuid().toString().remove("{").remove("}").remove("-");
_nodeTitle = nodeTitle;
_pIsRootNode = false;
_pIsFooterNode = false;
_pIsHasFooterPage = false;
_pParentNode = parent;
_pIsExpanderNode = false;
_pIsVisible = false;
}
ElaNavigationNode::~ElaNavigationNode()
{
qDeleteAll(_pChildrenNodes);
}
QString ElaNavigationNode::getNodeKey() const
{
return _nodeKey;
}
QString ElaNavigationNode::getNodeTitle() const
{
return _nodeTitle;
}
void ElaNavigationNode::setIsExpanded(bool isExpanded)
{
_isExpanded = isExpanded;
setChildVisible(isExpanded);
}
bool ElaNavigationNode::getIsExpanded() const
{
return _isExpanded;
}
void ElaNavigationNode::setChildVisible(bool isVisible)
{
if (isVisible)
{
for (auto node : _pChildrenNodes)
{
node->setIsVisible(isVisible);
if (node->getIsExpanderNode() && !node->getIsExpanded())
{
continue;
}
node->setChildVisible(isVisible);
}
}
else
{
for (auto node : _pChildrenNodes)
{
node->setChildVisible(isVisible);
node->setIsVisible(isVisible);
}
}
}
bool ElaNavigationNode::getIsHasChild() const
{
if (_pChildrenNodes.count() > 0)
{
return true;
}
return false;
}
bool ElaNavigationNode::getIsHasPageChild() const
{
if (_pChildrenNodes.count() == 0)
{
return false;
}
for (auto childNode : _pChildrenNodes)
{
if (!childNode->getIsExpanderNode())
{
return true;
}
if (childNode->getIsHasPageChild())
{
return true;
}
}
return false;
}
void ElaNavigationNode::appendChildNode(ElaNavigationNode* childNode)
{
if (_pIsExpanderNode)
{
_pChildrenNodes.append(childNode);
}
}
bool ElaNavigationNode::getIsChildHasKeyPoints() const
{
for (auto childNnode : _pChildrenNodes)
{
if (childNnode->getKeyPoints())
{
return true;
}
if (childNnode->getIsChildHasKeyPoints())
{
return true;
}
}
return false;
}
ElaNavigationNode* ElaNavigationNode::getOriginalNode()
{
if (this->getParentNode()->getIsRootNode())
{
return this;
}
else
{
ElaNavigationNode* originalNode = this->getParentNode();
while (!originalNode->getIsRootNode() && !originalNode->getParentNode()->getIsRootNode())
{
originalNode = originalNode->getParentNode();
}
return originalNode;
}
}
bool ElaNavigationNode::getIsChildNode(ElaNavigationNode* node)
{
if (_pChildrenNodes.count() > 0)
{
if (_pChildrenNodes.contains(node))
{
return true;
}
for (auto childNnode : _pChildrenNodes)
{
if (childNnode->getIsChildNode(node))
{
return true;
}
}
}
return false;
}
int ElaNavigationNode::getRow() const
{
if (_pParentNode)
{
return _pParentNode->getChildrenNodes().indexOf(const_cast<ElaNavigationNode*>(this));
}
return 0;
}
@@ -0,0 +1,52 @@
#ifndef ELANAVIGATIONNODE_H
#define ELANAVIGATIONNODE_H
#include <QModelIndex>
#include <QObject>
#include "Def.h"
class ElaNavigationNode : public QObject
{
Q_OBJECT
Q_PROPERTY_CREATE(QList<ElaNavigationNode*>, ChildrenNodes)
Q_PRIVATE_CREATE(ElaNavigationNode*, ParentNode)
Q_PROPERTY_CREATE(ElaIconType::IconName, Awesome)
Q_PROPERTY_CREATE(QModelIndex, ModelIndex)
Q_PROPERTY_CREATE(int, KeyPoints)
Q_PROPERTY_CREATE(int, Depth)
Q_PROPERTY_CREATE(bool, IsRootNode)
Q_PROPERTY_CREATE(bool, IsFooterNode)
Q_PROPERTY_CREATE(bool, IsHasFooterPage)
Q_PROPERTY_CREATE(bool, IsExpanderNode)
Q_PROPERTY_CREATE(bool, IsVisible)
public:
explicit ElaNavigationNode(QString nodeTitle, ElaNavigationNode* parent = nullptr);
~ElaNavigationNode();
QString getNodeKey() const;
QString getNodeTitle() const;
void setIsExpanded(bool isExpanded);
bool getIsExpanded() const;
void setChildVisible(bool isVisible);
bool getIsHasChild() const;
bool getIsHasPageChild() const;
void appendChildNode(ElaNavigationNode* childNode);
bool getIsChildHasKeyPoints() const;
ElaNavigationNode* getOriginalNode();
bool getIsChildNode(ElaNavigationNode* node);
int getRow() const;
private:
QString _nodeKey = "";
QString _nodeTitle = "";
bool _isExpanded{false};
};
#endif // ELANAVIGATIONNODE_H
@@ -0,0 +1,519 @@
#include "ElaNavigationStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include <QStyleOption>
#include "ElaNavigationModel.h"
#include "ElaNavigationNode.h"
#include "ElaNavigationView.h"
#include "ElaTheme.h"
ElaNavigationStyle::ElaNavigationStyle(QStyle* style)
{
_pOpacity = 1;
_pItemHeight = 40;
_pLastSelectMarkTop = 10.0;
_pLastSelectMarkBottom = 10.0;
_pSelectMarkTop = 10.0;
_pSelectMarkBottom = 10.0;
// Mark向上
_lastSelectMarkTopAnimation = new QPropertyAnimation(this, "pLastSelectMarkTop");
connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { _pNavigationView->viewport()->update(); });
_lastSelectMarkTopAnimation->setDuration(300);
_lastSelectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);
_selectMarkBottomAnimation = new QPropertyAnimation(this, "pSelectMarkBottom");
connect(_selectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { _pNavigationView->viewport()->update(); });
_selectMarkBottomAnimation->setDuration(300);
_selectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);
connect(_lastSelectMarkTopAnimation, &QPropertyAnimation::finished, this, [=]() {
_isSelectMarkDisplay = true;
_lastSelectedNode = nullptr;
_selectMarkBottomAnimation->setStartValue(0);
_selectMarkBottomAnimation->setEndValue(10);
_selectMarkBottomAnimation->start(); });
// Mark向下
_lastSelectMarkBottomAnimation = new QPropertyAnimation(this, "pLastSelectMarkBottom");
connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { _pNavigationView->viewport()->update(); });
_lastSelectMarkBottomAnimation->setDuration(300);
_lastSelectMarkBottomAnimation->setEasingCurve(QEasingCurve::InOutSine);
_selectMarkTopAnimation = new QPropertyAnimation(this, "pSelectMarkTop");
connect(_selectMarkTopAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) { _pNavigationView->viewport()->update(); });
_selectMarkTopAnimation->setDuration(300);
_selectMarkTopAnimation->setEasingCurve(QEasingCurve::InOutSine);
connect(_lastSelectMarkBottomAnimation, &QPropertyAnimation::finished, this, [=]() {
_isSelectMarkDisplay = true;
_lastSelectedNode = nullptr;
_selectMarkTopAnimation->setStartValue(0);
_selectMarkTopAnimation->setEndValue(10);
_selectMarkTopAnimation->start(); });
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaNavigationStyle::~ElaNavigationStyle()
{
}
void ElaNavigationStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelItemViewItem:
{
// Item背景
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
painter->save();
QModelIndex index = vopt->index;
ElaNavigationNode* node = static_cast<ElaNavigationNode*>(index.internalPointer());
if (this->_opacityAnimationTargetNode && node->getParentNode() == this->_opacityAnimationTargetNode)
{
painter->setOpacity(_pOpacity);
}
painter->setRenderHint(QPainter::Antialiasing);
QRect itemRect = vopt->rect;
itemRect.setTop(itemRect.top() + 2);
itemRect.setBottom(itemRect.bottom() - 2);
QPainterPath path;
path.addRoundedRect(itemRect, 8, 8);
if (vopt->state & QStyle::State_Selected)
{
if (index == _pPressIndex)
{
// 选中时点击
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
else
{
if (vopt->state & QStyle::State_MouseOver)
{
// 选中时覆盖
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
// 选中
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedAlpha));
}
}
}
else
{
if (index == _pPressIndex)
{
// 点击时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
if (vopt->state & QStyle::State_MouseOver)
{
// 覆盖时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
}
}
painter->restore();
}
return;
}
case QStyle::PE_PanelItemViewRow:
{
// 行背景
return;
}
case QStyle::PE_IndicatorBranch:
{
// Branch指示器
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaNavigationStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ShapedFrame:
{
// viewport视口外的其他区域背景
return;
}
case QStyle::CE_ItemViewItem:
{
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
// 背景绘制
this->drawPrimitive(QStyle::PE_PanelItemViewItem, option, painter, widget);
// 内容绘制
QRect itemRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
ElaNavigationNode* node = static_cast<ElaNavigationNode*>(vopt->index.internalPointer());
ElaNavigationModel* model = dynamic_cast<ElaNavigationModel*>(const_cast<QAbstractItemModel*>(vopt->index.model()));
if (this->_opacityAnimationTargetNode && node->getParentNode() == this->_opacityAnimationTargetNode)
{
painter->setOpacity(_pOpacity);
}
// 选中特效
if (_isSelectMarkDisplay && (node == model->getSelectedNode() || node == model->getSelectedExpandedNode()))
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(itemRect.x() + 3, itemRect.y() + _pSelectMarkTop, 3, itemRect.height() - _pSelectMarkTop - _pSelectMarkBottom), 3, 3);
}
if (node == _lastSelectedNode)
{
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(itemRect.x() + 3, itemRect.y() + _pLastSelectMarkTop, 3, itemRect.height() - _pLastSelectMarkTop - _pLastSelectMarkBottom), 3, 3);
}
// 图标绘制
painter->setPen(vopt->index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
if (node->getAwesome() != ElaIconType::None)
{
painter->save();
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->drawText(QRect(itemRect.x(), itemRect.y(), _iconAreaWidth, itemRect.height()), Qt::AlignCenter, QChar((unsigned short)node->getAwesome()));
painter->restore();
}
int viewWidth = widget->width();
// 文字绘制
painter->setPen(vopt->index == _pPressIndex ? ElaThemeColor(_themeMode, BasicTextPress) : ElaThemeColor(_themeMode, BasicText));
QRect textRect;
if (node->getAwesome() != ElaIconType::None)
{
textRect = QRect(itemRect.x() + _iconAreaWidth, itemRect.y(), itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _iconAreaWidth, itemRect.height());
}
else
{
textRect = QRect(itemRect.x() + _leftPadding, itemRect.y(), itemRect.width() - _textRightSpacing - _indicatorIconAreaWidth - _leftPadding, itemRect.height());
}
QString text = painter->fontMetrics().elidedText(node->getNodeTitle(), Qt::ElideRight, textRect.width());
painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
if (viewWidth > 260)
{
// 展开图标 KeyPoints
if (node->getIsExpanderNode())
{
if (node->getIsHasChild())
{
QRectF expandIconRect(itemRect.right() - _indicatorIconAreaWidth, itemRect.y(), 17, itemRect.height());
painter->save();
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->translate(expandIconRect.x() + (qreal)expandIconRect.width() / 2, expandIconRect.y() + (qreal)expandIconRect.height() / 2);
if (node == _expandAnimationTargetNode)
{
painter->rotate(_pRotate);
}
else
{
if (node->getIsExpanded())
{
//展开
painter->rotate(-180);
}
else
{
// 未展开
painter->rotate(0);
}
}
painter->translate(-expandIconRect.x() - (qreal)expandIconRect.width() / 2 + 1, -expandIconRect.y() - (qreal)expandIconRect.height() / 2);
painter->drawText(expandIconRect, Qt::AlignVCenter, QChar((unsigned short)ElaIconType::AngleDown));
painter->restore();
}
if (node->getIsChildHasKeyPoints())
{
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawEllipse(QPoint(itemRect.right() - 17, itemRect.y() + 12), 3, 3);
painter->restore();
}
}
else
{
int keyPoints = node->getKeyPoints();
if (keyPoints)
{
// KeyPoints
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::white);
painter->drawEllipse(QPoint(itemRect.right() - 26, itemRect.y() + itemRect.height() / 2), 10, 10);
painter->setBrush(ElaThemeColor(_themeMode, StatusDanger));
painter->drawEllipse(QPoint(itemRect.right() - 26, itemRect.y() + itemRect.height() / 2), 9, 9);
painter->setPen(QPen(Qt::white, 2));
QFont font = painter->font();
font.setBold(true);
if (keyPoints > 99)
{
keyPoints = 99;
}
if (keyPoints > 9)
{
font.setPixelSize(11);
}
else
{
font.setPixelSize(12);
}
painter->setFont(font);
painter->drawText(keyPoints > 9 ? itemRect.right() - 33 : itemRect.right() - 30, itemRect.y() + itemRect.height() / 2 + 4, QString::number(keyPoints));
painter->restore();
}
}
}
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QSize ElaNavigationStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
switch (type)
{
case QStyle::CT_ItemViewItem:
{
QSize itemSize = QProxyStyle::sizeFromContents(type, option, size, widget);
itemSize.setHeight(_pItemHeight);
return itemSize;
}
default:
{
break;
}
}
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
void ElaNavigationStyle::navigationNodeStateChange(QVariantMap data)
{
if (data.contains("Expand"))
{
ElaNavigationNode* lastExpandNode = _expandAnimationTargetNode;
_opacityAnimationTargetNode = data.value("Expand").value<ElaNavigationNode*>();
_expandAnimationTargetNode = _opacityAnimationTargetNode;
QPropertyAnimation* nodeOpacityAnimation = new QPropertyAnimation(this, "pOpacity");
connect(nodeOpacityAnimation, &QPropertyAnimation::finished, this, [=]() { _opacityAnimationTargetNode = nullptr; });
connect(nodeOpacityAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_pNavigationView->viewport()->update();
});
nodeOpacityAnimation->setDuration(600);
nodeOpacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
nodeOpacityAnimation->setKeyValueAt(0.4, 0);
nodeOpacityAnimation->setStartValue(0);
nodeOpacityAnimation->setEndValue(1);
nodeOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* rotateAnimation = new QPropertyAnimation(this, "pRotate");
connect(rotateAnimation, &QPropertyAnimation::finished, this, [=]() { _expandAnimationTargetNode = nullptr; });
connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_pNavigationView->viewport()->update();
});
rotateAnimation->setDuration(300);
rotateAnimation->setEasingCurve(QEasingCurve::InOutSine);
if (lastExpandNode == _expandAnimationTargetNode)
{
rotateAnimation->setStartValue(_pRotate);
}
else
{
rotateAnimation->setStartValue(0);
}
rotateAnimation->setEndValue(-180);
rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
else if (data.contains("Collapse"))
{
ElaNavigationNode* lastExpandNode = _expandAnimationTargetNode;
_opacityAnimationTargetNode = data.value("Collapse").value<ElaNavigationNode*>();
_expandAnimationTargetNode = _opacityAnimationTargetNode;
_pOpacity = 0;
QPropertyAnimation* rotateAnimation = new QPropertyAnimation(this, "pRotate");
connect(rotateAnimation, &QPropertyAnimation::finished, this, [=]() {
_pOpacity = 1;
_expandAnimationTargetNode = nullptr; });
connect(rotateAnimation, &QPropertyAnimation::valueChanged, this, [=](const QVariant& value) {
_pNavigationView->viewport()->update();
});
rotateAnimation->setDuration(300);
rotateAnimation->setEasingCurve(QEasingCurve::InOutSine);
if (lastExpandNode == _expandAnimationTargetNode)
{
rotateAnimation->setStartValue(_pRotate);
}
else
{
rotateAnimation->setStartValue(-180);
}
rotateAnimation->setEndValue(0);
rotateAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
else if (data.contains("SelectMarkChanged"))
{
_lastSelectedNode = data.value("LastSelectedNode").value<ElaNavigationNode*>();
ElaNavigationNode* selectedNode = data.value("SelectedNode").value<ElaNavigationNode*>();
bool direction = _compareItemY(selectedNode, _lastSelectedNode);
_pLastSelectMarkTop = 10;
_pLastSelectMarkBottom = 10;
_pSelectMarkTop = 10;
_pSelectMarkBottom = 10;
if (direction)
{
_lastSelectMarkTopAnimation->setStartValue(10);
_lastSelectMarkTopAnimation->setEndValue(0);
_lastSelectMarkTopAnimation->start();
_lastSelectMarkBottomAnimation->stop();
_selectMarkTopAnimation->stop();
_isSelectMarkDisplay = false;
}
else
{
_lastSelectMarkBottomAnimation->setStartValue(10);
_lastSelectMarkBottomAnimation->setEndValue(0);
_lastSelectMarkBottomAnimation->start();
_lastSelectMarkTopAnimation->stop();
_selectMarkBottomAnimation->stop();
_isSelectMarkDisplay = false;
}
}
}
bool ElaNavigationStyle::_compareItemY(ElaNavigationNode* node1, ElaNavigationNode* node2)
{
// 返回true 即node1 高于 node2
if (!node1)
{
return false;
}
if (!node2)
{
return true;
}
// 同一父节点
if (node1->getParentNode() == node2->getParentNode())
{
if (node1->getModelIndex().row() < node2->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
else
{
ElaNavigationNode* node1OriginalNode = node1->getOriginalNode();
ElaNavigationNode* node2OriginalNode = node2->getOriginalNode();
// 不同父节点 相同起源节点
if (node1OriginalNode == node2OriginalNode)
{
int node1Depth = node1->getDepth();
int node2Depth = node2->getDepth();
// 相同深度
if (node1Depth == node2Depth)
{
ElaNavigationNode* node1ParentNode = node1->getParentNode();
ElaNavigationNode* node2ParentNode = node2->getParentNode();
if (node1ParentNode->getModelIndex().row() < node2ParentNode->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
else
{
if (node1Depth < node2Depth)
{
ElaNavigationNode* node2ParentNode = node2->getParentNode();
while (node2ParentNode->getDepth() != node1Depth)
{
node2ParentNode = node2ParentNode->getParentNode();
}
// 父子节点关系
if (node1 == node2ParentNode)
{
return true;
}
if (node1->getModelIndex().row() < node2ParentNode->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
else
{
ElaNavigationNode* node1ParentNode = node1->getParentNode();
while (node1ParentNode->getDepth() != node2Depth)
{
node1ParentNode = node1ParentNode->getParentNode();
}
if (node2 == node1ParentNode)
{
return false;
}
if (node1ParentNode->getModelIndex().row() < node2->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
}
}
else
{
if (node1OriginalNode->getModelIndex().row() < node2OriginalNode->getModelIndex().row())
{
return true;
}
else
{
return false;
}
}
}
}
@@ -0,0 +1,48 @@
#ifndef ELANAVIGATIONSTYLE_H
#define ELANAVIGATIONSTYLE_H
#include <QModelIndex>
#include <QProxyStyle>
#include "Def.h"
class ElaNavigationNode;
class ElaNavigationView;
class QPropertyAnimation;
class ElaNavigationStyle : public QProxyStyle
{
Q_OBJECT
Q_PROPERTY_CREATE(qreal, Opacity)
Q_PROPERTY_CREATE(qreal, Rotate)
Q_PROPERTY_CREATE(int, ItemHeight)
Q_PRIVATE_CREATE(ElaNavigationView*, NavigationView)
Q_PROPERTY_CREATE(qreal, LastSelectMarkTop)
Q_PROPERTY_CREATE(qreal, LastSelectMarkBottom)
Q_PROPERTY_CREATE(qreal, SelectMarkTop)
Q_PROPERTY_CREATE(qreal, SelectMarkBottom)
Q_PRIVATE_CREATE(QModelIndex, PressIndex)
public:
explicit ElaNavigationStyle(QStyle* style = nullptr);
~ElaNavigationStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
void navigationNodeStateChange(QVariantMap data);
private:
ElaThemeType::ThemeMode _themeMode;
bool _isSelectMarkDisplay{true};
int _leftPadding{11};
int _iconAreaWidth{40};
int _textRightSpacing{3};
int _indicatorIconAreaWidth{34};
ElaNavigationNode* _opacityAnimationTargetNode{nullptr};
ElaNavigationNode* _expandAnimationTargetNode{nullptr};
ElaNavigationNode* _lastSelectedNode{nullptr};
QPropertyAnimation* _lastSelectMarkTopAnimation{nullptr};
QPropertyAnimation* _lastSelectMarkBottomAnimation{nullptr};
QPropertyAnimation* _selectMarkTopAnimation{nullptr};
QPropertyAnimation* _selectMarkBottomAnimation{nullptr};
bool _compareItemY(ElaNavigationNode* node1, ElaNavigationNode* node2);
};
#endif // ELANAVIGATIONSTYLE_H
@@ -0,0 +1,122 @@
#include "ElaNavigationView.h"
#include <QDebug>
#include <QHeaderView>
#include <QModelIndex>
#include <QMouseEvent>
#include <QPainter>
#include <QScrollBar>
#include <QScroller>
#include "ElaMenu.h"
#include "ElaNavigationModel.h"
#include "ElaNavigationNode.h"
#include "ElaNavigationStyle.h"
#include "ElaScrollBar.h"
ElaNavigationView::ElaNavigationView(QWidget* parent)
: QTreeView(parent)
{
setObjectName("ElaNavigationView");
setStyleSheet("#ElaNavigationView{background-color:transparent;}");
setAnimated(true);
setHeaderHidden(true);
setRootIsDecorated(false);
setExpandsOnDoubleClick(false);
setAutoScroll(false);
setMouseTracking(true);
setSelectionMode(QAbstractItemView::NoSelection);
// 滚动条设置
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ElaScrollBar* vScrollBar = new ElaScrollBar(this);
connect(vScrollBar, &ElaScrollBar::rangeAnimationFinished, this, [=]() {
doItemsLayout();
});
setVerticalScrollBar(vScrollBar);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ElaScrollBar* floatVScrollBar = new ElaScrollBar(vScrollBar, this);
floatVScrollBar->setIsAnimation(true);
_navigationStyle = new ElaNavigationStyle(this->style());
_navigationStyle->setNavigationView(this);
setStyle(_navigationStyle);
QScroller::grabGesture(this->viewport(), QScroller::LeftMouseButtonGesture);
QScroller* scroller = QScroller::scroller(this->viewport());
QScrollerProperties properties = scroller->scrollerProperties();
properties.setScrollMetric(QScrollerProperties::MousePressEventDelay, 0);
properties.setScrollMetric(QScrollerProperties::HorizontalOvershootPolicy, QScrollerProperties::OvershootAlwaysOff);
properties.setScrollMetric(QScrollerProperties::VerticalOvershootPolicy, QScrollerProperties::OvershootAlwaysOn);
properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.35);
properties.setScrollMetric(QScrollerProperties::OvershootScrollTime, 0.5);
properties.setScrollMetric(QScrollerProperties::FrameRate, QScrollerProperties::Fps60);
scroller->setScrollerProperties(properties);
connect(scroller, &QScroller::stateChanged, this, [=](QScroller::State newstate) {
if (newstate == QScroller::Pressed)
{
_navigationStyle->setPressIndex(indexAt(mapFromGlobal(QCursor::pos())));
viewport()->update();
}
else if (newstate == QScroller::Scrolling || newstate == QScroller::Inactive)
{
_navigationStyle->setPressIndex(QModelIndex());
}
});
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &ElaNavigationView::customContextMenuRequested, this, &ElaNavigationView::onCustomContextMenuRequested);
}
ElaNavigationView::~ElaNavigationView()
{
}
void ElaNavigationView::navigationNodeStateChange(QVariantMap data)
{
this->_navigationStyle->navigationNodeStateChange(data);
}
void ElaNavigationView::onCustomContextMenuRequested(const QPoint& pos)
{
QModelIndex posIndex = indexAt(pos);
if (!posIndex.isValid())
{
return;
}
ElaNavigationNode* posNode = static_cast<ElaNavigationNode*>(posIndex.internalPointer());
if (!posNode->getIsExpanderNode())
{
ElaMenu menu;
menu.setMenuItemHeight(27);
QAction* openAction = menu.addElaIconAction(ElaIconType::ObjectGroup, "在新窗口中打开");
connect(openAction, &QAction::triggered, this, [=]() {
Q_EMIT navigationOpenNewWindow(posNode->getNodeKey());
});
menu.exec(mapToGlobal(pos));
}
}
void ElaNavigationView::mouseDoubleClickEvent(QMouseEvent* event)
{
_navigationStyle->setPressIndex(indexAt(event->pos()));
viewport()->update();
QTreeView::mouseDoubleClickEvent(event);
}
void ElaNavigationView::mouseReleaseEvent(QMouseEvent* event)
{
QTreeView::mouseReleaseEvent(event);
if (event->button() == Qt::LeftButton)
{
QModelIndex index = indexAt(event->pos());
if (index.isValid())
{
Q_EMIT navigationClicked(index);
}
_navigationStyle->setPressIndex(QModelIndex());
}
}
@@ -0,0 +1,30 @@
#ifndef ELANAVIGATIONVIEW_H
#define ELANAVIGATIONVIEW_H
#include <QObject>
#include <QTreeView>
class ElaScrollBar;
class ElaNavigationStyle;
class ElaNavigationView : public QTreeView
{
Q_OBJECT
public:
explicit ElaNavigationView(QWidget* parent = nullptr);
~ElaNavigationView();
void navigationNodeStateChange(QVariantMap data);
Q_SLOT void onCustomContextMenuRequested(const QPoint& pos);
Q_SIGNALS:
Q_SIGNAL void navigationClicked(const QModelIndex& index);
Q_SIGNAL void navigationOpenNewWindow(QString nodeKey);
protected:
virtual void mouseDoubleClickEvent(QMouseEvent* event) override;
virtual void mouseReleaseEvent(QMouseEvent* event) override;
private:
ElaNavigationStyle* _navigationStyle{nullptr};
};
#endif // ELANAVIGATIONVIEW_H
@@ -0,0 +1,51 @@
#include "ElaPivotModel.h"
ElaPivotModel::ElaPivotModel(QObject* parent)
: QAbstractListModel{parent}
{
}
ElaPivotModel::~ElaPivotModel()
{
}
void ElaPivotModel::appendPivot(QString pivot)
{
if (!pivot.isEmpty())
{
beginInsertRows(QModelIndex(), _pivotList.count(), _pivotList.count());
_pivotList.append(pivot);
endInsertRows();
return;
}
}
void ElaPivotModel::removePivot(QString pivot)
{
if (_pivotList.contains(pivot))
{
int index = _pivotList.lastIndexOf(pivot);
beginRemoveRows(QModelIndex(), index, index);
_pivotList.removeAt(index);
endRemoveRows();
}
}
int ElaPivotModel::getPivotListCount() const
{
return _pivotList.count();
}
int ElaPivotModel::rowCount(const QModelIndex& parent) const
{
return _pivotList.count();
}
QVariant ElaPivotModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole)
{
return _pivotList[index.row()];
}
return QVariant();
}
@@ -0,0 +1,26 @@
#ifndef ELAPIVOTMODEL_H
#define ELAPIVOTMODEL_H
#include <QAbstractListModel>
class ElaPivotModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ElaPivotModel(QObject* parent = nullptr);
~ElaPivotModel();
void appendPivot(QString pivot);
void removePivot(QString pivot);
int getPivotListCount() const;
protected:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override;
private:
QStringList _pivotList;
};
#endif // ELAPIVOTMODEL_H
@@ -0,0 +1,112 @@
#include "ElaPivotStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaPivotStyle::ElaPivotStyle(QStyle* style)
{
_pCurrentIndex = -1;
_pPivotSpacing = 5;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) {
_themeMode = themeMode;
});
}
ElaPivotStyle::~ElaPivotStyle()
{
}
void ElaPivotStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelItemViewRow:
{
return;
}
case QStyle::PE_Widget:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaPivotStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ShapedFrame:
{
// viewport视口外的其他区域背景
return;
}
case QStyle::CE_ItemViewItem:
{
if (const QStyleOptionViewItem* vopt = qstyleoption_cast<const QStyleOptionViewItem*>(option))
{
// 内容绘制
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);
QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
textRect.adjust(0, 0, 0, -5);
// 文字绘制
if (!vopt->text.isEmpty())
{
if (_pPressIndex == vopt->index)
{
painter->setPen(ElaThemeColor(_themeMode, BasicTextPress));
}
else
{
if (_pCurrentIndex == vopt->index.row() || vopt->state.testFlag(QStyle::State_MouseOver))
{
painter->setPen(ElaThemeColor(_themeMode, BasicText));
}
else
{
painter->setPen(ElaThemeColor(_themeMode, BasicTextNoFocus));
}
}
painter->drawText(textRect, Qt::AlignCenter, vopt->text);
}
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
int ElaPivotStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_FocusFrameHMargin:
{
return _pPivotSpacing;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
const QColor& ElaPivotStyle::getMarkColor()
{
return ElaThemeColor(_themeMode, PrimaryNormal);
}
@@ -0,0 +1,27 @@
#ifndef ELAPIVOTSTYLE_H
#define ELAPIVOTSTYLE_H
#include <QModelIndex>
#include <QProxyStyle>
#include "Def.h"
class ElaPivotStyle : public QProxyStyle
{
Q_OBJECT
Q_PRIVATE_CREATE(QModelIndex, PressIndex)
Q_PRIVATE_CREATE(int, CurrentIndex)
Q_PRIVATE_CREATE(int, PivotSpacing)
public:
explicit ElaPivotStyle(QStyle* style = nullptr);
~ElaPivotStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
const QColor& getMarkColor();
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELAPIVOTSTYLE_H
@@ -0,0 +1,111 @@
#include "ElaPivotView.h"
#include <QMouseEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include "ElaPivotStyle.h"
#include "ElaScrollBar.h"
ElaPivotView::ElaPivotView(QWidget* parent)
: QListView(parent)
{
_pMarkX = 0;
_pMarkWidth = 40;
_pMarkAnimationWidth = 0;
setObjectName("ElaPivotView");
setStyleSheet("#ElaPivotView{background-color:transparent;}");
setMouseTracking(true);
setVerticalScrollBar(new ElaScrollBar(this));
setHorizontalScrollBar(new ElaScrollBar(this));
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
}
ElaPivotView::~ElaPivotView()
{
}
void ElaPivotView::doCurrentIndexChangedAnimation(const QModelIndex& index)
{
if (index.row() >= 0)
{
QRect newIndexRect = visualRect(index);
QPropertyAnimation* markAnimation = new QPropertyAnimation(this, "pMarkX");
connect(markAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
update();
});
markAnimation->setDuration(300);
markAnimation->setEasingCurve(QEasingCurve::InOutSine);
if (_pPivotStyle->getCurrentIndex() >= 0)
{
markAnimation->setStartValue(_pMarkX);
markAnimation->setEndValue(newIndexRect.center().x() - _pMarkWidth / 2);
}
else
{
markAnimation->setStartValue(newIndexRect.center().x());
markAnimation->setEndValue(newIndexRect.center().x() - _pMarkWidth / 2);
QPropertyAnimation* markWidthAnimation = new QPropertyAnimation(this, "pMarkAnimationWidth");
markWidthAnimation->setDuration(300);
markWidthAnimation->setEasingCurve(QEasingCurve::InOutSine);
markWidthAnimation->setStartValue(0);
markWidthAnimation->setEndValue(_pMarkWidth);
markWidthAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
markAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
else
{
QRect newIndexRect = visualRect(model()->index(_pPivotStyle->getCurrentIndex(), 0));
QPropertyAnimation* markAnimation = new QPropertyAnimation(this, "pMarkX");
connect(markAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
update();
});
markAnimation->setDuration(300);
markAnimation->setEasingCurve(QEasingCurve::InOutSine);
markAnimation->setStartValue(_pMarkX);
markAnimation->setEndValue(newIndexRect.center().x());
markAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* markWidthAnimation = new QPropertyAnimation(this, "pMarkAnimationWidth");
markWidthAnimation->setDuration(300);
markWidthAnimation->setEasingCurve(QEasingCurve::InOutSine);
markWidthAnimation->setStartValue(_pMarkAnimationWidth);
markWidthAnimation->setEndValue(0);
markWidthAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
setCurrentIndex(index);
}
void ElaPivotView::mouseDoubleClickEvent(QMouseEvent* event)
{
_pPivotStyle->setPressIndex(indexAt(event->pos()));
viewport()->update();
QListView::mouseDoubleClickEvent(event);
}
void ElaPivotView::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
_pPivotStyle->setPressIndex(QModelIndex());
viewport()->update();
}
QListView::mouseReleaseEvent(event);
}
void ElaPivotView::paintEvent(QPaintEvent* event)
{
QPainter painter(viewport());
QRect viewPortRect = viewport()->rect();
painter.save();
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
painter.setBrush(_pPivotStyle->getMarkColor());
painter.drawRoundedRect(QRect(_pMarkX, viewPortRect.bottom() - 4, _pMarkAnimationWidth, 3), 3, 3);
painter.restore();
QListView::paintEvent(event);
}
@@ -0,0 +1,26 @@
#ifndef ELAPIVOTVIEW_H
#define ELAPIVOTVIEW_H
#include <QListView>
#include "stdafx.h"
class ElaPivotStyle;
class ElaPivotView : public QListView
{
Q_OBJECT
Q_PROPERTY_CREATE(int, MarkX)
Q_PRIVATE_CREATE(int, MarkWidth)
Q_PROPERTY_CREATE(int, MarkAnimationWidth)
Q_PRIVATE_CREATE(ElaPivotStyle*, PivotStyle)
public:
explicit ElaPivotView(QWidget* parent = nullptr);
~ElaPivotView();
void doCurrentIndexChangedAnimation(const QModelIndex& index);
protected:
void mouseDoubleClickEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
};
#endif // ELAPIVOTVIEW_H
@@ -0,0 +1,66 @@
#include "ElaPlainTextEditStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include <QtMath>
#include "ElaTheme.h"
ElaPlainTextEditStyle::ElaPlainTextEditStyle(QStyle* style)
{
_pExpandMarkWidth = 0;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaPlainTextEditStyle::~ElaPlainTextEditStyle()
{
}
void ElaPlainTextEditStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ShapedFrame:
{
if (const QStyleOptionFrame* fopt = qstyleoption_cast<const QStyleOptionFrame*>(option))
{
//背景绘制
QRect editRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
// 边框绘制
painter->setBrush(ElaThemeColor(_themeMode, BasicBorder));
painter->drawRoundedRect(editRect, 6, 6);
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawRoundedRect(QRectF(editRect.x() + 1.5, editRect.y() + 1.5, editRect.width() - 3, editRect.height() - 3), 6, 6);
// 底边线绘制
painter->setBrush(ElaThemeColor(_themeMode, BasicHemline));
QPainterPath path;
path.moveTo(6, editRect.height());
path.lineTo(editRect.width() - 6, editRect.height());
path.arcTo(QRectF(editRect.width() - 12, editRect.height() - 12, 12, 12), -90, 45);
path.lineTo(6 - 3 * std::sqrt(2), editRect.height() - (6 - 3 * std::sqrt(2)));
path.arcTo(QRectF(0, editRect.height() - 12, 12, 12), 270, 45);
path.closeSubpath();
painter->drawPath(path);
//焦点指示器
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(editRect.width() / 2 - _pExpandMarkWidth, editRect.height() - 2.5, _pExpandMarkWidth * 2, 2.5), 2, 2);
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
@@ -0,0 +1,20 @@
#ifndef ELAPLAINTEXTEDITSTYLE_H
#define ELAPLAINTEXTEDITSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaPlainTextEditStyle : public QProxyStyle
{
Q_OBJECT
Q_PROPERTY_CREATE(qreal, ExpandMarkWidth)
public:
explicit ElaPlainTextEditStyle(QStyle* style = nullptr);
~ElaPlainTextEditStyle();
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELAPLAINTEXTEDITSTYLE_H
@@ -0,0 +1,242 @@
#include "ElaPopularCardFloater.h"
#include <QEvent>
#include <QGraphicsOpacityEffect>
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include "ElaPopularCard.h"
#include "ElaPopularCardPrivate.h"
#include "ElaPushButton.h"
#include "ElaTheme.h"
ElaPopularCardFloater::ElaPopularCardFloater(ElaPopularCard* card, ElaPopularCardPrivate* cardPrivate, QWidget* parent)
: QWidget{parent}
{
_card = card;
_cardPrivate = cardPrivate;
_pHoverOpacity = 0;
_pHoverYOffset = 0;
setObjectName("ElaPopularCardFloater");
setStyleSheet("#ElaPopularCardFloater{background-color:transparent}");
setMouseTracking(true);
_overButton = new ElaPushButton("获取", this);
_opacityEffect = new QGraphicsOpacityEffect(_overButton);
_opacityEffect->setOpacity(1);
_overButton->setGraphicsEffect(_opacityEffect);
_overButton->move(0, 0);
_overButton->setLightDefaultColor(ElaThemeColor(ElaThemeType::Light, PrimaryNormal));
_overButton->setLightHoverColor(ElaThemeColor(ElaThemeType::Light, PrimaryHover));
_overButton->setLightPressColor(ElaThemeColor(ElaThemeType::Light, PrimaryPress));
_overButton->setLightTextColor(Qt::white);
_overButton->setDarkDefaultColor(ElaThemeColor(ElaThemeType::Dark, PrimaryNormal));
_overButton->setDarkHoverColor(ElaThemeColor(ElaThemeType::Dark, PrimaryHover));
_overButton->setDarkPressColor(ElaThemeColor(ElaThemeType::Dark, PrimaryPress));
_overButton->setDarkTextColor(Qt::white);
_overButton->setMinimumSize(0, 0);
_overButton->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
connect(_overButton, &ElaPushButton::clicked, _card, &ElaPopularCard::popularCardButtonClicked);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
setVisible(false);
}
ElaPopularCardFloater::~ElaPopularCardFloater()
{
}
void ElaPopularCardFloater::showFloater()
{
_isHideAnimationFinished = true;
_pHoverYOffset = 6;
_pHoverOpacity = 1;
_opacityEffect->setOpacity(1);
QPropertyAnimation* geometryAnimation = new QPropertyAnimation(this, "geometry");
connect(geometryAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
update();
});
geometryAnimation->setEasingCurve(QEasingCurve::OutQuad);
geometryAnimation->setDuration(300);
QRect cardGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
QRect endGeometry = _calculateTargetGeometry(cardGeometry);
QRect startGeometry = QRect(endGeometry.x() + _floatGeometryOffset, endGeometry.y() + _floatGeometryOffset, _card->width(), _card->height());
geometryAnimation->setStartValue(startGeometry);
geometryAnimation->setEndValue(endGeometry);
geometryAnimation->start(QAbstractAnimation::DeleteWhenStopped);
//Button动画
QPropertyAnimation* buttonAnimation = new QPropertyAnimation(_overButton, "geometry");
buttonAnimation->setEasingCurve(QEasingCurve::OutQuad);
buttonAnimation->setDuration(300);
buttonAnimation->setStartValue(_cardPrivate->_interactiveTipsBaseRect);
buttonAnimation->setEndValue(_cardPrivate->_buttonTargetRect);
buttonAnimation->start(QAbstractAnimation::DeleteWhenStopped);
setVisible(true);
}
void ElaPopularCardFloater::hideFloater()
{
if (!_isHideAnimationFinished)
{
return;
}
_isHideAnimationFinished = false;
QPropertyAnimation* geometryAnimation = new QPropertyAnimation(this, "geometry");
connect(geometryAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
QRect endGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
geometryAnimation->setEndValue(endGeometry);
});
connect(geometryAnimation, &QPropertyAnimation::finished, this, [=]() {
_cardPrivate->_isFloating = false;
setVisible(false);
_card->update();
});
geometryAnimation->setEasingCurve(QEasingCurve::InOutSine);
geometryAnimation->setDuration(300);
QRect endGeometry = QRect(_card->mapTo(_cardPrivate->_pCardFloatArea, QPoint(0, 0)), _card->size());
geometryAnimation->setStartValue(geometry());
geometryAnimation->setEndValue(endGeometry);
geometryAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* opacityAnimation = new QPropertyAnimation(this, "pHoverOpacity");
opacityAnimation->setDuration(300);
opacityAnimation->setStartValue(_pHoverOpacity);
opacityAnimation->setEndValue(0);
opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
//内容调整动画
QPropertyAnimation* hoverAnimation = new QPropertyAnimation(this, "pHoverYOffset");
connect(hoverAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
update();
});
hoverAnimation->setDuration(300);
hoverAnimation->setStartValue(_pHoverYOffset);
hoverAnimation->setEndValue(0);
hoverAnimation->start(QAbstractAnimation::DeleteWhenStopped);
//Button动画
QPropertyAnimation* buttonAnimation = new QPropertyAnimation(_overButton, "geometry");
buttonAnimation->setEasingCurve(QEasingCurve::InOutSine);
buttonAnimation->setDuration(300);
buttonAnimation->setStartValue(_overButton->geometry());
QRectF endRect = _cardPrivate->_interactiveTipsBaseRect;
endRect.adjust(0, 6, 0, 6);
buttonAnimation->setEndValue(endRect);
buttonAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* buttonOpacityAnimation = new QPropertyAnimation(_overButton->graphicsEffect(), "opacity");
buttonOpacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
buttonOpacityAnimation->setDuration(350);
buttonOpacityAnimation->setStartValue(1);
buttonOpacityAnimation->setEndValue(0);
buttonOpacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
bool ElaPopularCardFloater::event(QEvent* event)
{
switch (event->type())
{
case QEvent::Leave:
{
hideFloater();
break;
}
case QEvent::MouseButtonRelease:
{
Q_EMIT _card->popularCardClicked();
break;
}
default:
{
break;
}
}
return QWidget::event(event);
}
void ElaPopularCardFloater::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing);
// 阴影绘制
painter.setOpacity(_pHoverOpacity);
QRect shadowRect = rect();
shadowRect.adjust(0, 0, 0, -_pHoverYOffset);
eTheme->drawEffectShadow(&painter, shadowRect, _cardPrivate->_shadowBorderWidth, _cardPrivate->_pBorderRadius);
QRectF foregroundRect(_cardPrivate->_shadowBorderWidth, _cardPrivate->_shadowBorderWidth - _pHoverYOffset + 1, width() - 2 * _cardPrivate->_shadowBorderWidth, height() - 2 * _cardPrivate->_shadowBorderWidth);
QRectF cardForegroundRect(_cardPrivate->_shadowBorderWidth, _cardPrivate->_shadowBorderWidth - _cardPrivate->_pHoverYOffset + 1, _card->width() - 2 * _cardPrivate->_shadowBorderWidth, _card->height() - 2 * _cardPrivate->_shadowBorderWidth);
//背景绘制
painter.setOpacity(1);
painter.setPen(ElaThemeColor(_themeMode, PopupBorderHover));
painter.setBrush(ElaThemeColor(_themeMode, DialogBase));
painter.drawRoundedRect(foregroundRect, _cardPrivate->_pBorderRadius, _cardPrivate->_pBorderRadius);
painter.setClipRect(foregroundRect);
//图片绘制
painter.save();
QRectF pixRect(foregroundRect.x() + cardForegroundRect.height() * 0.15, foregroundRect.y() + cardForegroundRect.height() * 0.15, cardForegroundRect.height() * 0.7, cardForegroundRect.height() * 0.7);
QPainterPath pixPath;
pixPath.addRoundedRect(pixRect, 4, 4);
painter.setClipPath(pixPath);
painter.drawPixmap(pixRect, _cardPrivate->_pCardPixmap, _cardPrivate->_pCardPixmap.rect());
painter.restore();
//文字绘制
//Title
painter.setPen(ElaThemeColor(_themeMode, BasicText));
QFont font = painter.font();
font.setWeight(QFont::Bold);
font.setPixelSize(15);
painter.setFont(font);
int titleHeight = painter.fontMetrics().height();
QRectF titleRect(pixRect.right() + _cardPrivate->_textHSpacing, pixRect.y(), _floatGeometryOffset * 2 + cardForegroundRect.width() - pixRect.width() - _cardPrivate->_textHSpacing * 2 - cardForegroundRect.height() * 0.15 - _cardPrivate->_buttonTargetRect.width(), titleHeight);
QString titleText = painter.fontMetrics().elidedText(_cardPrivate->_pTitle, Qt::ElideRight, titleRect.width());
painter.drawText(titleRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, titleText);
//SubTitle
font.setWeight(QFont::DemiBold);
font.setPixelSize(13);
painter.setFont(font);
int subTitleHeight = painter.fontMetrics().height();
QRectF subTitleRect(pixRect.right() + _cardPrivate->_textHSpacing, titleRect.bottom() + _cardPrivate->_textVSpacing, _floatGeometryOffset * 2 + cardForegroundRect.width() - pixRect.width() - _cardPrivate->_textHSpacing * 2 - cardForegroundRect.height() * 0.15 - _cardPrivate->_buttonTargetRect.width(), subTitleHeight);
QString subTitleText = painter.fontMetrics().elidedText(_cardPrivate->_pSubTitle, Qt::ElideRight, subTitleRect.width());
painter.drawText(subTitleRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, subTitleText);
//DetailedText
painter.setPen(ElaThemeColor(_themeMode, BasicDetailsText));
int detailedTextHeight = painter.fontMetrics().height() * 2 + 2;
QRectF detailedTextRect(pixRect.x(), pixRect.bottom() + cardForegroundRect.height() * 0.15, cardForegroundRect.width() + 2 * _floatGeometryOffset - _cardPrivate->_textHSpacing - cardForegroundRect.height() * 0.15, detailedTextHeight);
QString detailedText = painter.fontMetrics().elidedText(_cardPrivate->_pDetailedText, Qt::ElideRight, detailedTextRect.width() * 1.9);
painter.drawText(detailedTextRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, detailedText);
//分割线绘制
painter.setPen(ElaThemeColor(_themeMode, BasicBaseLine));
painter.drawLine(foregroundRect.x(), detailedTextRect.bottom() + 5, foregroundRect.right(), detailedTextRect.bottom() + 5);
//CardFloatPixmap
painter.drawPixmap(QRect(pixRect.x(), detailedTextRect.bottom() + 15, cardForegroundRect.bottom() + _floatGeometryOffset + 90 - detailedTextRect.bottom() - 15 - _cardPrivate->_shadowBorderWidth - 10, cardForegroundRect.bottom() + _floatGeometryOffset + 90 - detailedTextRect.bottom() - 15 - _cardPrivate->_shadowBorderWidth - 10), _cardPrivate->_pCardFloatPixmap);
painter.restore();
}
QRect ElaPopularCardFloater::_calculateTargetGeometry(QRect cardGeometry)
{
QRect targetGeometry = cardGeometry;
targetGeometry.adjust(-_floatGeometryOffset, -_floatGeometryOffset, _floatGeometryOffset, 90);
QRect windowRect = _cardPrivate->_pCardFloatArea->rect();
if (targetGeometry.bottom() > windowRect.bottom())
{
int offset = targetGeometry.bottom() - windowRect.bottom();
targetGeometry.adjust(0, -offset, 0, -offset);
}
if (targetGeometry.top() < windowRect.top())
{
int offset = targetGeometry.top() - windowRect.top();
targetGeometry.adjust(0, -offset, 0, -offset);
}
return targetGeometry;
}
@@ -0,0 +1,39 @@
#ifndef ELAPOPULARCARDFLOATER_H
#define ELAPOPULARCARDFLOATER_H
#include <QWidget>
#include "Def.h"
class ElaPushButton;
class ElaPopularCard;
class ElaPopularCardPrivate;
class QGraphicsOpacityEffect;
class ElaPopularCardFloater : public QWidget
{
Q_OBJECT
Q_PROPERTY_CREATE(qreal, HoverYOffset);
Q_PROPERTY_CREATE(qreal, HoverOpacity);
public:
explicit ElaPopularCardFloater(ElaPopularCard* card, ElaPopularCardPrivate* cardPrivate, QWidget* parent = nullptr);
~ElaPopularCardFloater();
void showFloater();
void hideFloater();
protected:
virtual bool event(QEvent* event) override;
virtual void paintEvent(QPaintEvent* event) override;
private:
friend class ElaPopularCard;
ElaThemeType::ThemeMode _themeMode;
ElaPushButton* _overButton{nullptr};
QGraphicsOpacityEffect* _opacityEffect{nullptr};
bool _isHideAnimationFinished{true};
ElaPopularCard* _card{nullptr};
ElaPopularCardPrivate* _cardPrivate{nullptr};
QRect _calculateTargetGeometry(QRect cardGeometry);
int _floatGeometryOffset{25};
};
#endif // ELAPOPULARCARDFLOATER_H
@@ -0,0 +1,155 @@
#include "ElaProgressBarStyle.h"
#include <QDebug>
#include <QPainter>
#include <QStyleOption>
#include "ElaTheme.h"
ElaProgressBarStyle::ElaProgressBarStyle(QStyle* style)
{
setProperty("busyStartValue", 0);
setProperty("busyEndValue", 0);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaProgressBarStyle::~ElaProgressBarStyle()
{
}
void ElaProgressBarStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_ProgressBarGroove:
{
//背景轨道
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicChute));
painter->drawRoundedRect(option->rect, 3, 3);
painter->restore();
return;
}
case QStyle::CE_ProgressBarContents:
{
//滑块
const QStyleOptionProgressBar* popt = qstyleoption_cast<const QStyleOptionProgressBar*>(option);
if (!popt)
{
break;
}
QRect contentRect = popt->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
const bool inverted = popt->invertedAppearance;
bool reverse = popt->direction == Qt::RightToLeft;
if (inverted)
{
reverse = !reverse;
}
if (popt->minimum == 0 && popt->maximum == 0)
{
//忙碌动画
int startValue = this->property("busyStartValue").toInt();
if (startValue < 0)
{
startValue = 0;
}
int endValue = this->property("busyEndValue").toInt();
if (popt->state & QStyle::State_Horizontal)
{
if (endValue > contentRect.width())
{
endValue = contentRect.width();
}
int busyWidth = endValue - startValue;
if (reverse)
{
painter->translate((contentRect.x() + contentRect.width()) / 2, contentRect.y());
painter->rotate(180);
painter->translate(-(contentRect.x() + contentRect.width()) / 2, -contentRect.y() - contentRect.height() * 0.90);
}
painter->drawRoundedRect(QRectF(startValue, contentRect.y(), busyWidth, contentRect.height()), 3, 3);
}
else
{
if (endValue > contentRect.height())
{
endValue = contentRect.height();
}
int busyHeight = endValue - startValue;
painter->drawRoundedRect(QRectF(contentRect.x(), contentRect.height() - endValue, contentRect.width(), busyHeight), 3, 3);
}
}
else
{
qreal ratio = popt->progress / (qreal)(popt->maximum - popt->minimum);
if (popt->state & QStyle::State_Horizontal)
{
if (reverse)
{
painter->translate((contentRect.x() + contentRect.width()) / 2, contentRect.y());
painter->rotate(180);
painter->translate(-(contentRect.x() + contentRect.width()) / 2, -contentRect.y() - contentRect.height() * 0.90);
}
painter->drawRoundedRect(QRectF(contentRect.x(), contentRect.y(), contentRect.width() * ratio, contentRect.height()), 3, 3);
}
else
{
painter->drawRoundedRect(QRectF(contentRect.x(), contentRect.y() + contentRect.height() * (1 - ratio), contentRect.width(), contentRect.height() * ratio), 3, 3);
}
}
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QRect ElaProgressBarStyle::subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const
{
switch (element)
{
case QStyle::SE_ProgressBarGroove:
case QStyle::SE_ProgressBarContents:
{
QRect textRect = subElementRect(SE_ProgressBarLabel, option, widget);
const QStyleOptionProgressBar* popt = qstyleoption_cast<const QStyleOptionProgressBar*>(option);
if (!popt)
{
break;
}
QRect contentRect = popt->rect;
int width = contentRect.width();
int height = contentRect.height();
if (popt->state & QStyle::State_Horizontal)
{
contentRect.setTop(contentRect.top() + height * 0.45);
contentRect.setBottom(contentRect.bottom() - height * 0.30);
if (!(popt->minimum == 0 && popt->maximum == 0))
{
contentRect.setWidth(contentRect.width() - textRect.width());
}
}
else
{
contentRect.setLeft(contentRect.left() + width * 0.375);
contentRect.setRight(contentRect.right() - width * 0.375);
}
return contentRect;
}
default:
{
break;
}
}
return QProxyStyle::subElementRect(element, option, widget);
}
@@ -0,0 +1,20 @@
#ifndef ELAPROGRESSBARSTYLE_H
#define ELAPROGRESSBARSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaProgressBarStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaProgressBarStyle(QStyle* style = nullptr);
~ElaProgressBarStyle();
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELAPROGRESSBARSTYLE_H
@@ -0,0 +1,104 @@
#include "ElaRadioButtonStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QStyleOption>
#include "ElaTheme.h"
ElaRadioButtonStyle::ElaRadioButtonStyle(QStyle* style)
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaRadioButtonStyle::~ElaRadioButtonStyle()
{
}
void ElaRadioButtonStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case PE_IndicatorRadioButton:
{
const QStyleOptionButton* bopt = qstyleoption_cast<const QStyleOptionButton*>(option);
if (!bopt)
{
break;
}
QRect buttonRect = bopt->rect;
buttonRect.adjust(1, 1, -1, -1);
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
if (bopt->state & QStyle::State_Off)
{
painter->setPen(QPen(ElaThemeColor(_themeMode, BasicBorder), 1.5));
if (bopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHover));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
}
painter->drawEllipse(QPointF(buttonRect.center().x() + 1, buttonRect.center().y() + 1), 8.5, 8.5);
}
else
{
painter->setPen(Qt::NoPen);
// 外圆形
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawEllipse(QPointF(buttonRect.center().x() + 1, buttonRect.center().y() + 1), buttonRect.width() / 2, buttonRect.width() / 2);
// 内圆形
painter->setBrush(ElaThemeColor(_themeMode, BasicTextInvert));
if (bopt->state & QStyle::State_Sunken)
{
if (bopt->state & QStyle::State_MouseOver)
{
painter->drawEllipse(QPointF(buttonRect.center().x() + 1, buttonRect.center().y() + 1), buttonRect.width() / 4.5, buttonRect.width() / 4.5);
}
}
else
{
if (bopt->state & QStyle::State_MouseOver)
{
painter->drawEllipse(QPointF(buttonRect.center().x() + 1, buttonRect.center().y() + 1), buttonRect.width() / 3.5, buttonRect.width() / 3.5);
}
else
{
painter->drawEllipse(QPointF(buttonRect.center().x() + 1, buttonRect.center().y() + 1), buttonRect.width() / 4, buttonRect.width() / 4);
}
}
}
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
int ElaRadioButtonStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_ExclusiveIndicatorWidth:
{
return 20;
}
case QStyle::PM_ExclusiveIndicatorHeight:
{
return 20;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
@@ -0,0 +1,20 @@
#ifndef ELARADIOBUTTONSTYLE_H
#define ELARADIOBUTTONSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaRadioButtonStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaRadioButtonStyle(QStyle* style = nullptr);
~ElaRadioButtonStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELARADIOBUTTONSTYLE_H
@@ -0,0 +1,192 @@
#include "ElaScrollBarStyle.h"
#include <QPainter>
#include <QPainterPath>
#include <QPropertyAnimation>
#include <QStyleOptionSlider>
#include <QtMath>
#include "ElaScrollBar.h"
#include "ElaTheme.h"
ElaScrollBarStyle::ElaScrollBarStyle(QStyle* style)
{
_pIsExpand = false;
_pOpacity = 0;
_pScrollBar = nullptr;
_pSliderExtent = 2.4;
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaScrollBarStyle::~ElaScrollBarStyle()
{
}
void ElaScrollBarStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
//QStyle::SC_ScrollBarGroove QStyle::SC_ScrollBarAddLine QStyle::SC_ScrollBarSubLine上指示器
switch (control)
{
case QStyle::CC_ScrollBar:
{
if (const QStyleOptionSlider* sopt = qstyleoption_cast<const QStyleOptionSlider*>(option))
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::NoPen);
QRect scrollBarRect = sopt->rect;
if (_pIsExpand)
{
// 背景绘制
painter->setOpacity(_pOpacity);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawRoundedRect(scrollBarRect, 6, 6);
//指示器绘制 center()在此处不适用 存在外围边距宽度 需手动计算
int sideLength = 8;
painter->setBrush(ElaThemeColor(_themeMode, ScrollBarHandle));
if (sopt->orientation == Qt::Horizontal)
{
QRect leftIndicatorRect = subControlRect(control, sopt, QStyle::SC_ScrollBarSubLine, widget);
QRect rightIndicatorRect = subControlRect(control, sopt, QStyle::SC_ScrollBarAddLine, widget);
// 左三角
qreal centerLeftX = leftIndicatorRect.x() + leftIndicatorRect.width() / 2;
qreal centerRightX = rightIndicatorRect.x() + rightIndicatorRect.width() / 2;
qreal centerY = leftIndicatorRect.height() / 2;
QPainterPath leftPath;
leftPath.moveTo(centerLeftX - qCos(30 * M_PI / 180.0) * sideLength / 2, centerY);
leftPath.lineTo(centerLeftX + qCos(30 * M_PI / 180.0) * sideLength / 2, centerY + sideLength / 2);
leftPath.lineTo(centerLeftX + qCos(30 * M_PI / 180.0) * sideLength / 2, centerY - sideLength / 2);
leftPath.closeSubpath();
painter->drawPath(leftPath);
// 右三角
QPainterPath rightPath;
rightPath.moveTo(centerRightX + qCos(30 * M_PI / 180.0) * sideLength / 2, centerY);
rightPath.lineTo(centerRightX - qCos(30 * M_PI / 180.0) * sideLength / 2, centerY + sideLength / 2);
rightPath.lineTo(centerRightX - qCos(30 * M_PI / 180.0) * sideLength / 2, centerY - sideLength / 2);
rightPath.closeSubpath();
painter->drawPath(rightPath);
}
else
{
QRect upIndicatorRect = subControlRect(control, sopt, QStyle::SC_ScrollBarSubLine, widget);
QRect downIndicatorRect = subControlRect(control, sopt, QStyle::SC_ScrollBarAddLine, widget);
qreal centerToTop = (sideLength / 2) / qCos(30 * M_PI / 180.0);
qreal centerToBottom = (sideLength / 2) * qTan(30 * M_PI / 180.0);
// 上三角
qreal centerX = upIndicatorRect.width() / 2.0;
qreal centerUpY = upIndicatorRect.center().y() + 2;
qreal centerDownY = downIndicatorRect.center().y() + 2;
QPainterPath upPath;
upPath.moveTo(centerX, centerUpY - centerToTop);
upPath.lineTo(centerX + sideLength / 2, centerUpY + centerToBottom);
upPath.lineTo(centerX - sideLength / 2, centerUpY + centerToBottom);
upPath.closeSubpath();
painter->drawPath(upPath);
// 下三角
QPainterPath downPath;
downPath.moveTo(centerX, centerDownY + centerToBottom);
downPath.lineTo(centerX + sideLength / 2, centerDownY - centerToTop);
downPath.lineTo(centerX - sideLength / 2, centerDownY - centerToTop);
downPath.closeSubpath();
painter->drawPath(downPath);
}
}
painter->setOpacity(1);
//滑块绘制
QRectF sliderRect = subControlRect(control, sopt, QStyle::SC_ScrollBarSlider, widget);
painter->setBrush(ElaThemeColor(_themeMode, ScrollBarHandle));
if (sopt->orientation == Qt::Horizontal)
{
sliderRect.setRect(sliderRect.x(), sliderRect.bottom() - _sliderMargin - _pSliderExtent, sliderRect.width(), _pSliderExtent);
}
else
{
sliderRect.setRect(sliderRect.right() - _sliderMargin - _pSliderExtent, sliderRect.y(), _pSliderExtent, sliderRect.height());
}
painter->drawRoundedRect(sliderRect, _pSliderExtent / 2.0, _pSliderExtent / 2.0);
painter->restore();
}
return;
}
default:
{
break;
}
}
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
int ElaScrollBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
// qDebug() << metric << QProxyStyle::pixelMetric(metric, option, widget);
switch (metric)
{
case QStyle::PM_ScrollBarExtent:
{
return _scrollBarExtent;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
int ElaScrollBarStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const
{
if (hint == QStyle::SH_ScrollBar_LeftClickAbsolutePosition)
{
return true;
}
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
void ElaScrollBarStyle::startExpandAnimation(bool isExpand)
{
if (isExpand)
{
_pIsExpand = true;
QPropertyAnimation* opacityAnimation = new QPropertyAnimation(this, "pOpacity");
connect(opacityAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
_pScrollBar->update();
});
opacityAnimation->setDuration(250);
opacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
opacityAnimation->setStartValue(_pOpacity);
opacityAnimation->setEndValue(1);
opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* extentAnimation = new QPropertyAnimation(this, "pSliderExtent");
extentAnimation->setDuration(250);
extentAnimation->setEasingCurve(QEasingCurve::InOutSine);
extentAnimation->setStartValue(_pSliderExtent);
extentAnimation->setEndValue(_scrollBarExtent - 2 * _sliderMargin);
extentAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
else
{
QPropertyAnimation* opacityAnimation = new QPropertyAnimation(this, "pOpacity");
connect(opacityAnimation, &QPropertyAnimation::finished, this, [=]() {
_pIsExpand = false;
});
connect(opacityAnimation, &QPropertyAnimation::valueChanged, this, [=]() {
_pScrollBar->update();
});
opacityAnimation->setDuration(250);
opacityAnimation->setEasingCurve(QEasingCurve::InOutSine);
opacityAnimation->setStartValue(_pOpacity);
opacityAnimation->setEndValue(0);
opacityAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QPropertyAnimation* extentAnimation = new QPropertyAnimation(this, "pSliderExtent");
extentAnimation->setDuration(250);
extentAnimation->setEasingCurve(QEasingCurve::InOutSine);
extentAnimation->setStartValue(_pSliderExtent);
extentAnimation->setEndValue(2.4);
extentAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
}
@@ -0,0 +1,28 @@
#ifndef ELASCROLLBARSTYLE_H
#define ELASCROLLBARSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaScrollBar;
class ElaScrollBarStyle : public QProxyStyle
{
Q_OBJECT
Q_PRIVATE_CREATE(bool, IsExpand)
Q_PROPERTY_CREATE(qreal, Opacity)
Q_PROPERTY_CREATE(qreal, SliderExtent)
Q_PRIVATE_CREATE(ElaScrollBar*, ScrollBar)
public:
explicit ElaScrollBarStyle(QStyle* style = nullptr);
~ElaScrollBarStyle();
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override;
void startExpandAnimation(bool isExpand);
private:
ElaThemeType::ThemeMode _themeMode;
qreal _sliderMargin{2.5};
int _scrollBarExtent{10};
};
#endif // ELASCROLLBARSTYLE_H
@@ -0,0 +1,164 @@
#include "ElaSliderStyle.h"
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyleOptionSlider>
#include "ElaTheme.h"
ElaSliderStyle::ElaSliderStyle(QStyle* style)
{
setProperty("circleRadius", 0.01);
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaSliderStyle::~ElaSliderStyle()
{
}
void ElaSliderStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
switch (control)
{
case QStyle::CC_Slider:
{
const QStyleOptionSlider* sopt = qstyleoption_cast<const QStyleOptionSlider*>(option);
if (!sopt)
{
break;
}
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QRect sliderRect = sopt->rect;
QRect sliderHandleRect = subControlRect(control, sopt, SC_SliderHandle, widget);
sliderHandleRect.adjust(1, 1, -1, -1);
// 滑槽
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, BasicChute));
if (sopt->orientation == Qt::Horizontal)
{
// 未滑过
painter->drawRoundedRect(QRect(sliderRect.x() + sliderRect.height() / 8, sliderRect.y() + sliderRect.height() * 0.375, sliderRect.width() - sliderRect.height() / 4, sliderRect.height() / 4), sliderRect.height() / 8, sliderRect.height() / 8);
// 已滑过
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRect(sliderRect.x() + sliderRect.height() / 8, sliderRect.y() + sliderRect.height() * 0.375, sliderHandleRect.x(), sliderRect.height() / 4), sliderRect.height() / 8, sliderRect.height() / 8);
}
else
{
// 未滑过
painter->drawRoundedRect(QRect(sliderRect.x() + sliderRect.width() * 0.375, sliderRect.y() + sliderRect.width() / 8, sliderRect.width() / 4, sliderRect.height() - sliderRect.width() / 4), sliderRect.width() / 8, sliderRect.width() / 8);
// 已滑过
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRect(sliderRect.x() + sliderRect.width() * 0.375, sliderHandleRect.y(), sliderRect.width() / 4, sliderRect.height() - sliderRect.width() / 8 - sliderHandleRect.y()), sliderRect.width() / 8, sliderRect.width() / 8);
}
// 滑块
// 外圆形
painter->setPen(ElaThemeColor(_themeMode, BasicBorder));
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), sliderHandleRect.width() / 2, sliderHandleRect.width() / 2);
// 内圆形
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
if (_lastState == 0)
{
_lastState = sopt->state;
}
if (_circleRadius == 0)
{
_circleRadius = sliderHandleRect.width() / 3.8;
}
if (sopt->activeSubControls == SC_SliderHandle)
{
if (sopt->state & QStyle::State_Sunken)
{
if (sopt->state & QStyle::State_MouseOver)
{
if (!_lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(sliderHandleRect.width() / 2.8, sliderHandleRect.width() / 4.5, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
}
else
{
if (sopt->state & QStyle::State_MouseOver)
{
if (!_lastState.testFlag(QStyle::State_MouseOver))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 2.8, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
if (_lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 2.8, const_cast<QWidget*>(widget));
_lastState = sopt->state;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
}
}
else
{
if (_lastState.testFlag(QStyle::State_MouseOver) || _lastState.testFlag(QStyle::State_Sunken))
{
_startRadiusAnimation(_circleRadius, sliderHandleRect.width() / 3.8, const_cast<QWidget*>(widget));
_lastState &= ~QStyle::State_MouseOver;
_lastState &= ~QStyle::State_Sunken;
}
painter->drawEllipse(QPointF(sliderHandleRect.center().x() + 1, sliderHandleRect.center().y() + 1), _circleRadius, _circleRadius);
}
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
int ElaSliderStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
switch (metric)
{
case QStyle::PM_SliderLength:
{
return 20;
}
case QStyle::PM_SliderThickness:
{
return 20;
}
default:
{
break;
}
}
return QProxyStyle::pixelMetric(metric, option, widget);
}
int ElaSliderStyle::styleHint(StyleHint hint, const QStyleOption* option, const QWidget* widget, QStyleHintReturn* returnData) const
{
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
{
return Qt::LeftButton;
}
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
void ElaSliderStyle::_startRadiusAnimation(qreal startRadius, qreal endRadius, QWidget* widget) const
{
ElaSliderStyle* style = const_cast<ElaSliderStyle*>(this);
QPropertyAnimation* circleRadiusAnimation = new QPropertyAnimation(style, "circleRadius");
connect(circleRadiusAnimation, &QPropertyAnimation::valueChanged, style, [=](const QVariant& value) {
this->_circleRadius = value.toReal();
widget->update(); });
circleRadiusAnimation->setEasingCurve(QEasingCurve::InOutSine);
circleRadiusAnimation->setStartValue(startRadius);
circleRadiusAnimation->setEndValue(endRadius);
circleRadiusAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
@@ -0,0 +1,24 @@
#ifndef ELASLIDERSTYLE_H
#define ELASLIDERSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaSliderStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaSliderStyle(QStyle* style = nullptr);
~ElaSliderStyle();
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
int styleHint(StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
mutable QStyle::State _lastState{0};
mutable qreal _circleRadius{0};
void _startRadiusAnimation(qreal startRadius, qreal endRadius, QWidget* widget) const;
};
#endif // ELASLIDERSTYLE_H
@@ -0,0 +1,173 @@
#include "ElaSpinBoxStyle.h"
#include <QDebug>
#include <QPainter>
#include <QPainterPath>
#include <QStyleOptionSpinBox>
#include "ElaTheme.h"
ElaSpinBoxStyle::ElaSpinBoxStyle(QStyle* style)
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaSpinBoxStyle::~ElaSpinBoxStyle()
{
}
void ElaSpinBoxStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const
{
switch (control)
{
case QStyle::CC_SpinBox:
{
const QStyleOptionSpinBox* sopt = qstyleoption_cast<const QStyleOptionSpinBox*>(option);
if (!sopt)
{
break;
}
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
//背景
painter->setPen(ElaThemeColor(_themeMode, BasicBorder));
painter->setBrush(ElaThemeColor(_themeMode, BasicBase));
painter->drawRoundedRect(sopt->rect, 4, 4);
//添加按钮
QRect addLineRect = subControlRect(control, sopt, SC_ScrollBarAddLine, widget);
if (sopt->activeSubControls == SC_ScrollBarAddLine)
{
if (sopt->state & QStyle::State_Sunken && sopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicPressAlpha));
}
else
{
if (sopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHoverAlpha));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseDeep));
}
}
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseDeep));
}
QPainterPath addLinePath;
addLinePath.moveTo(addLineRect.topLeft());
addLinePath.lineTo(addLineRect.bottomLeft());
addLinePath.lineTo(addLineRect.right() - 4, addLineRect.bottom());
addLinePath.arcTo(QRectF(addLineRect.right() - 8, addLineRect.bottom() - 8, 8, 8), -90, 90);
addLinePath.lineTo(addLineRect.right(), addLineRect.y() + 4);
addLinePath.arcTo(QRectF(addLineRect.right() - 8, addLineRect.y(), 8, 8), 0, 90);
addLinePath.closeSubpath();
painter->drawPath(addLinePath);
//减少按钮
QRect subLineRect = subControlRect(control, sopt, SC_ScrollBarSubLine, widget);
if (sopt->activeSubControls == SC_ScrollBarSubLine)
{
if (sopt->state & QStyle::State_Sunken && sopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicPressAlpha));
}
else
{
if (sopt->state & QStyle::State_MouseOver)
{
painter->setBrush(ElaThemeColor(_themeMode, BasicHoverAlpha));
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseDeep));
}
}
}
else
{
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseDeep));
}
QPainterPath subLinePath;
subLinePath.moveTo(subLineRect.topRight());
subLinePath.lineTo(subLineRect.x() + 4, subLineRect.y());
subLinePath.arcTo(QRectF(subLineRect.x(), subLineRect.y(), 8, 8), 90, 90);
subLinePath.lineTo(subLineRect.x(), subLineRect.bottom() - 4);
subLinePath.arcTo(QRectF(subLineRect.x(), subLineRect.bottom() - 8, 8, 8), 180, 90);
subLinePath.lineTo(subLineRect.bottomRight());
subLinePath.closeSubpath();
painter->drawPath(subLinePath);
//底边线
if (sopt->state & QStyle::State_HasFocus)
{
painter->setPen(QPen(ElaThemeColor(_themeMode, PrimaryNormal), 2));
painter->drawLine(subLineRect.right() + 1, subLineRect.y() + subLineRect.height() - 2, addLineRect.left() - 1, subLineRect.y() + subLineRect.height() - 2);
}
else
{
painter->setPen(ElaThemeColor(_themeMode, BasicHemline));
painter->drawLine(subLineRect.right() + 1, subLineRect.y() + subLineRect.height() - 1, addLineRect.left() - 1, subLineRect.y() + subLineRect.height() - 1);
}
//添加图标
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->setPen(ElaThemeColor(_themeMode, BasicText));
painter->drawText(addLineRect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::Plus));
//减小图标
painter->drawText(subLineRect, Qt::AlignCenter, QChar((unsigned short)ElaIconType::Minus));
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawComplexControl(control, option, painter, widget);
}
QRect ElaSpinBoxStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const
{
QRect rect = QProxyStyle::subControlRect(cc, opt, sc, widget);
switch (cc)
{
case CC_SpinBox:
{
switch (sc)
{
case SC_ScrollBarAddLine:
{
//增加按钮
QRect spinBoxRect = QProxyStyle::subControlRect(cc, opt, SC_SpinBoxFrame, widget);
return QRect(spinBoxRect.width() - spinBoxRect.height(), 0, spinBoxRect.height(), spinBoxRect.height());
}
case SC_ScrollBarSubLine:
{
//减少按钮
QRect spinBoxRect = QProxyStyle::subControlRect(cc, opt, SC_SpinBoxFrame, widget);
return QRect(0, 0, spinBoxRect.height(), spinBoxRect.height());
}
case SC_SpinBoxEditField:
{
QRect spinBoxRect = QProxyStyle::subControlRect(cc, opt, SC_SpinBoxFrame, widget);
return QRect(spinBoxRect.height(), 0, spinBoxRect.width() - 2 * spinBoxRect.height(), spinBoxRect.height());
}
default:
{
break;
}
}
break;
}
default:
{
break;
}
}
return rect;
}
@@ -0,0 +1,20 @@
#ifndef ELASPINBOXSTYLE_H
#define ELASPINBOXSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaSpinBoxStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaSpinBoxStyle(QStyle* style = nullptr);
~ElaSpinBoxStyle();
void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex* opt, SubControl sc, const QWidget* widget) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELASPINBOXSTYLE_H
@@ -0,0 +1,80 @@
#include "ElaStatusBarStyle.h"
#include <QDebug>
#include <QPainter>
#include <QStyleOption>
#include "ElaTheme.h"
ElaStatusBarStyle::ElaStatusBarStyle(QStyle* style)
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaStatusBarStyle::~ElaStatusBarStyle()
{
}
void ElaStatusBarStyle::drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::PE_PanelStatusBar:
{
//背景绘制
QRect statusBarRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter->setPen(ElaThemeColor(_themeMode, BasicBorder));
painter->setBrush(ElaThemeColor(_themeMode, BasicBaseAlpha));
painter->drawRect(statusBarRect);
painter->restore();
return;
}
case QStyle::PE_FrameStatusBarItem:
{
//间隔符绘制
QRect statusBarItemRect = option->rect;
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter->setPen(Qt::NoPen);
painter->setBrush(ElaThemeColor(_themeMode, PrimaryNormal));
painter->drawRoundedRect(QRectF(statusBarItemRect.right() - 3, statusBarItemRect.y() + statusBarItemRect.height() * 0.1, 3, statusBarItemRect.height() - statusBarItemRect.height() * 0.2), 2, 2);
painter->restore();
return;
}
default:
{
break;
}
}
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
void ElaStatusBarStyle::drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget) const
{
switch (element)
{
case QStyle::CE_SizeGrip:
{
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QSize ElaStatusBarStyle::sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const
{
//qDebug() << type << QProxyStyle::sizeFromContents(type, option, size, widget);
return QProxyStyle::sizeFromContents(type, option, size, widget);
}
int ElaStatusBarStyle::pixelMetric(PixelMetric metric, const QStyleOption* option, const QWidget* widget) const
{
return QProxyStyle::pixelMetric(metric, option, widget);
}
@@ -0,0 +1,22 @@
#ifndef ELASTATUSBARSTYLE_H
#define ELASTATUSBARSTYLE_H
#include <QProxyStyle>
#include "Def.h"
class ElaStatusBarStyle : public QProxyStyle
{
Q_OBJECT
public:
explicit ElaStatusBarStyle(QStyle* style = nullptr);
~ElaStatusBarStyle();
void drawPrimitive(PrimitiveElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, const QWidget* widget = nullptr) const override;
QSize sizeFromContents(ContentsType type, const QStyleOption* option, const QSize& size, const QWidget* widget) const override;
int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELASTATUSBARSTYLE_H
@@ -0,0 +1,31 @@
#include "ElaSuggestBoxSearchViewContainer.h"
#include <QPainter>
#include "ElaTheme.h"
ElaSuggestBoxSearchViewContainer::ElaSuggestBoxSearchViewContainer(QWidget* parent)
: QWidget{parent}
{
setContentsMargins(8, 8, 8, 8);
setObjectName("ElaSuggestBoxSearchViewBaseWidget");
setStyleSheet("#ElaSuggestBoxSearchViewBaseWidget{background-color:transparent}");
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaSuggestBoxSearchViewContainer::~ElaSuggestBoxSearchViewContainer()
{
}
void ElaSuggestBoxSearchViewContainer::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
painter.save();
painter.setRenderHints(QPainter::Antialiasing);
eTheme->drawEffectShadow(&painter, rect(), 6, 8);
painter.setPen(ElaThemeColor(_themeMode, PopupBorder));
painter.setBrush(ElaThemeColor(_themeMode, PopupBase));
QRect foregroundRect(6, 0, rect().width() - 2 * 6, rect().height() - 6);
painter.drawRoundedRect(foregroundRect, 8, 8);
painter.restore();
}
@@ -0,0 +1,21 @@
#ifndef ELASUGGESTBOXSEARCHVIEWCONTAINER_H
#define ELASUGGESTBOXSEARCHVIEWCONTAINER_H
#include <QWidget>
#include "Def.h"
class ElaSuggestBoxSearchViewContainer : public QWidget
{
Q_OBJECT
public:
explicit ElaSuggestBoxSearchViewContainer(QWidget* parent = nullptr);
~ElaSuggestBoxSearchViewContainer();
protected:
virtual void paintEvent(QPaintEvent* event) override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELASUGGESTBOXSEARCHVIEWCONTAINER_H
@@ -0,0 +1,79 @@
#include "ElaSuggestDelegate.h"
#include <QPainter>
#include <QPainterPath>
#include "ElaSuggestBoxPrivate.h"
#include "ElaSuggestModel.h"
#include "ElaTheme.h"
ElaSuggestDelegate::ElaSuggestDelegate(QObject* parent)
: QStyledItemDelegate{parent}
{
_themeMode = eTheme->getThemeMode();
connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { _themeMode = themeMode; });
}
ElaSuggestDelegate::~ElaSuggestDelegate()
{
}
void ElaSuggestDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
int margin = 2;
QStyleOptionViewItem viewOption(option);
initStyleOption(&viewOption, index);
ElaSuggestModel* model = dynamic_cast<ElaSuggestModel*>(const_cast<QAbstractItemModel*>(index.model()));
ElaSuggestion* suggest = model->getSearchSuggestion(index.row());
if (option.state.testFlag(QStyle::State_HasFocus))
{
viewOption.state &= ~QStyle::State_HasFocus;
}
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QPainterPath path;
QRect optionRect = option.rect;
optionRect.adjust(margin * 2, margin, -margin * 2, -margin);
path.addRoundedRect(optionRect, 8, 8);
if (option.state & QStyle::State_Selected)
{
if (option.state & QStyle::State_MouseOver)
{
//选中时覆盖
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedHoverAlpha));
}
else
{
//选中
painter->fillPath(path, ElaThemeColor(_themeMode, BasicSelectedAlpha));
}
}
else
{
if (option.state & QStyle::State_MouseOver)
{
//覆盖时颜色
painter->fillPath(path, ElaThemeColor(_themeMode, BasicHoverAlpha));
}
}
//文字绘制
painter->setPen(ElaThemeColor(_themeMode, BasicText));
painter->drawText(option.rect.x() + 37, option.rect.y() + 25, suggest->getSuggestText());
//图标绘制
if (suggest->getElaIcon() != ElaIconType::None)
{
QFont iconFont = QFont("ElaAwesome");
iconFont.setPixelSize(17);
painter->setFont(iconFont);
painter->drawText(option.rect.x() + 11, option.rect.y() + 26, QChar((unsigned short)suggest->getElaIcon()));
}
painter->restore();
}
QSize ElaSuggestDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(40);
return size;
}
@@ -0,0 +1,22 @@
#ifndef ELASUGGESTDELEGATE_H
#define ELASUGGESTDELEGATE_H
#include <QStyledItemDelegate>
#include "Def.h"
class ElaSuggestDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ElaSuggestDelegate(QObject* parent = nullptr);
~ElaSuggestDelegate();
protected:
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
private:
ElaThemeType::ThemeMode _themeMode;
};
#endif // ELASUGGESTDELEGATE_H
@@ -0,0 +1,46 @@
#include "ElaSuggestModel.h"
ElaSuggestModel::ElaSuggestModel(QObject* parent)
: QAbstractListModel{parent}
{
}
ElaSuggestModel::~ElaSuggestModel()
{
}
int ElaSuggestModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return _suggestionVector.count();
}
QVariant ElaSuggestModel::data(const QModelIndex& index, int role) const
{
return QVariant();
}
void ElaSuggestModel::setSearchSuggestion(QVector<ElaSuggestion*> suggestionVector)
{
if (suggestionVector.count() == 0)
{
return;
}
beginResetModel();
_suggestionVector = suggestionVector;
endResetModel();
}
void ElaSuggestModel::clearSearchNode()
{
this->_suggestionVector.clear();
}
ElaSuggestion* ElaSuggestModel::getSearchSuggestion(int row)
{
if (row >= _suggestionVector.count())
{
return nullptr;
}
return _suggestionVector[row];
}
@@ -0,0 +1,24 @@
#ifndef ELASUGGESTMODEL_H
#define ELASUGGESTMODEL_H
#include <QAbstractListModel>
#include "Def.h"
class ElaSuggestion;
class ElaSuggestModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ElaSuggestModel(QObject* parent = nullptr);
~ElaSuggestModel();
int rowCount(const QModelIndex& parent) const;
QVariant data(const QModelIndex& index, int role) const;
void setSearchSuggestion(QVector<ElaSuggestion*> suggestionVector);
void clearSearchNode();
ElaSuggestion* getSearchSuggestion(int row);
private:
QVector<ElaSuggestion*> _suggestionVector; //符合搜索的节点
};
#endif // ELASUGGESTMODEL_H

Some files were not shown because too many files have changed in this diff Show More