Files
cbh/ElaWidgetTools/DeveloperComponents/ElaMenuStyle.cpp
2025-09-20 01:41:33 +08:00

204 lines
9.6 KiB
C++

#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 = 8;
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: {
// 图标宽度
_iconWidth = _pMenuItemHeight * 0.7;
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);
}