Skip to content

Commit

Permalink
sync: from linuxdeepin/qt5integration
Browse files Browse the repository at this point in the history
Synchronize source files from linuxdeepin/qt5integration.

Source-pull-request: linuxdeepin/qt5integration#233
  • Loading branch information
deepin-ci-robot committed Aug 1, 2024
1 parent 0256e91 commit a470a53
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 16 deletions.
224 changes: 209 additions & 15 deletions styleplugins/chameleon/chameleonstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
#include <QBitmap>
#include <QTableView>
#include <QStyledItemDelegate>
#include <QVariantAnimation>
#include <QProgressBar>
#include <QTimer>
#include <DSpinBox>
#include <DTreeView>
#include <DIconButton>
Expand Down Expand Up @@ -122,6 +125,57 @@ inline static bool isTheClassObject(QObject *object)
#endif
}

ChameleonMovementAnimation::ChameleonMovementAnimation(QWidget *targetWidget)
: QVariantAnimation(targetWidget)
{
setDuration(150);

connect(this, &QVariantAnimation::valueChanged, targetWidget, [this] (const QVariant &value) {
if (!isRuning())
return;

const auto rect = value.toRect();
Q_ASSERT(!m_currentRect.isEmpty());
this->targetWidget()->update(m_currentRect.united(rect));
m_currentRect = rect;
});
connect(this, &QVariantAnimation::finished, targetWidget, [this] {
Q_ASSERT(m_currentRect == m_targetRect);
// 确保动画结束后有一帧的刷新,因为在菜单的动画过程中会修改菜单文字的 opacity
// 对opacity的修改会根据是否处于动画状态进行判断,因此要确保动画结束后刷新它
this->targetWidget()->update(m_currentRect);
});
}

QWidget *ChameleonMovementAnimation::targetWidget() const
{
return qobject_cast<QWidget*>(parent());
}

void ChameleonMovementAnimation::setTargetRect(const QRect &rect)
{
if (m_targetRect == rect)
return;

m_lastTargetRect = m_targetRect;
m_targetRect = rect;

if (m_currentRect.isEmpty())
m_currentRect = m_lastTargetRect;

// 当目标绘制区域改变时,说明当前正在进行的动画过期了,应该重新开始动画
stop();
setStartValue(m_currentRect);
setEndValue(rect);

if (!m_currentRect.isEmpty()) {
start();
} else {
// 这种情况说明不需要进行动画,往往发生在首次显示,这时候应该直接绘制到目标区域
m_currentRect = rect;
}
}

ChameleonStyle::ChameleonStyle()
: DStyle()
{
Expand Down Expand Up @@ -1370,7 +1424,17 @@ void ChameleonStyle::drawControl(QStyle::ControlElement element, const QStyleOpt
frameRadius = qMin(height / 2, 4);
}
p->setBrush(getColor(opt, DPalette::ObviousBackground, w));
p->setPen(Qt::NoPen);
p->drawRoundedRect(opt->rect, frameRadius, frameRadius);

QPen pen;
pen.setColor(DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType
? QColor(255, 255, 255, 0.15 * 255)
: QColor(0, 0, 0, 0.15 * 255));
pen.setWidth(1);
p->setPen(pen);
p->setBrush(Qt::NoBrush);
p->drawRoundedRect(opt->rect.marginsRemoved(QMargins(1, 1, 1, 1)), frameRadius, frameRadius);
}
return;
}
Expand Down Expand Up @@ -1410,15 +1474,33 @@ void ChameleonStyle::drawControl(QStyle::ControlElement element, const QStyleOpt
linear.setColorAt(0, startColor);
linear.setColorAt(1, endColor);
linear.setSpread(QGradient::PadSpread);
p->setBrush(QBrush(linear));
p->setBrush(startColor);

if (progBar->textVisible) {
QPainterPath pathRect;
pathRect.addRect(rect);
QPainterPath pathRoundRect;
pathRoundRect.addRoundedRect(opt->rect, frameRadius, frameRadius);
QPainterPath inter = pathRoundRect.intersected(pathRect);

QPainterPath clipPath;
clipPath.addRoundedRect(rect, frameRadius, frameRadius);
p->setClipPath(clipPath);
p->setClipping(true);
p->drawPath(inter);
p->setClipping(false);

QPen pen;
pen.setColor(DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::DarkType
? QColor(255, 255, 255, 0.3 * 255)
: QColor(0, 0, 0, 0.3 * 255));
pen.setWidth(1);
p->setPen(pen);
p->setBrush(Qt::NoBrush);
p->setClipping(true);
p->drawRoundedRect(rect.marginsRemoved(QMargins(1, 1, 1, 1)), frameRadius, frameRadius);
p->setClipping(false);

} else {
//进度条高度 <= 8px && 进度条宽度 <= 8px && value有效
if (rect.height() <= ProgressBar_MinimumStyleHeight &&
Expand All @@ -1444,8 +1526,70 @@ void ChameleonStyle::drawControl(QStyle::ControlElement element, const QStyleOpt
path2.arcTo(endRect, 90, -180);
p->drawPath(path2);
}
} else
} else {
QPainterPath clipPath;
clipPath.addRoundedRect(opt->rect, frameRadius, frameRadius);
p->setClipPath(clipPath);
p->setClipping(true);
p->drawRoundedRect(rect, frameRadius, frameRadius);
p->setClipping(false);

QPen pen;
pen.setColor(QColor(0, 0, 0, 0.3 * 255));
pen.setWidth(1);
p->setPen(pen);
p->setBrush(Qt::NoBrush);
p->setClipping(true);
p->drawRoundedRect(rect.marginsRemoved(QMargins(1, 1, 1, 1)), frameRadius, frameRadius);
p->setClipping(false);
}
}

// 进度条光斑
int spotWidth = 200;
if (rect.width() >= spotWidth) {
p->setPen(Qt::NoPen);

QObject *progressbar = opt->styleObject;
if (!progressbar)
progressbar = dynamic_cast<QObject *>(p->device());

if (m_progressAni.isEmpty() || !m_progressAni.value(progressbar))
return;

QColor shadowColor(0, 0, 0, int(0.15 * 255));
QColor spotColor(255, 255, 255, int(0.5 * 255));
QColor highLightColor(getColor(opt, DPalette::Highlight));

QPointF pointStart(m_progressAni.value(progressbar)->currentValue().toRect().left(), m_progressAni.value(progressbar)->currentValue().toRect().center().y());
QPointF pointEnd(m_progressAni.value(progressbar)->currentValue().toRect().right(), m_progressAni.value(progressbar)->currentValue().toRect().center().y());
QLinearGradient linear(pointStart, pointEnd);
linear.setColorAt(0, highLightColor);
linear.setColorAt(0.35, shadowColor);
linear.setColorAt(0.5, spotColor);
linear.setColorAt(0.65, shadowColor);
linear.setColorAt(1, highLightColor);
linear.setSpread(QGradient::PadSpread);
linear.setInterpolationMode(QLinearGradient::InterpolationMode::ColorInterpolation);
p->setBrush(linear);

QPainterPath clipPath;
clipPath.addRoundedRect(rect, frameRadius, frameRadius);
p->setClipping(true);
p->drawRect(m_progressAni.value(progressbar)->currentValue().toRect().marginsRemoved(QMargins(1, 1, 1, 1)));
p->setClipping(false);

if (m_progressAni.value(progressbar)->state() == QVariantAnimation::Running)
return;

QRect startRect(rect.x() - spotWidth, rect.y(), spotWidth, rect.height());
m_progressAni.value(progressbar)->setStartValue(startRect);
QRect endRect = startRect;
endRect.moveRight(rect.width() + spotWidth);
m_progressAni.value(progressbar)->setEndValue(endRect);
m_progressAni.value(progressbar)->setDuration(2500);
m_progressAni.value(progressbar)->setEasingCurve(QEasingCurve::InQuad);
m_progressAni.value(progressbar)->start();
}
}
return;
Expand Down Expand Up @@ -2757,7 +2901,7 @@ bool ChameleonStyle::drawMenuBarItem(const QStyleOptionMenuItem *option, QRect &
return true;
}

void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter *painter, QStyleOptionMenuItem::MenuItemType type) const
ChameleonMovementAnimation *ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter *painter, QStyleOptionMenuItem::MenuItemType type) const
{
QBrush color;
bool selected = (option->state & QStyle::State_Enabled) && option->state & QStyle::State_Selected;
Expand All @@ -2766,7 +2910,7 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
painter->setPen(Qt::NoPen);
painter->setBrush(getColor(option, QPalette::Highlight));
painter->drawRect(option->rect);
return;
return nullptr;
}

// 清理旧的阴影
Expand All @@ -2791,8 +2935,6 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
}

if (selected) {
color = option->palette.highlight();

// draw shadow
if (type == QStyleOptionMenuItem::Normal) {
if (option->styleObject) {
Expand All @@ -2807,9 +2949,7 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
}
}
}

painter->fillRect(option->rect, color);
} else {
} else do {
color = option->palette.window().color();

if (color.color().isValid() && color.color().alpha() != 0) {
Expand Down Expand Up @@ -2846,14 +2986,14 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
}

if (!option->styleObject)
return;
break;

// 为上一个item绘制阴影
const QRect shadow = option->styleObject->property("_d_menu_shadow_rect").toRect();

// 判断阴影rect是否在自己的区域
if (!option->rect.contains(shadow.center()))
return;
break;

static QColor shadow_color;
static QPixmap shadow_pixmap;
Expand All @@ -2870,11 +3010,47 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
if (!shadow_pixmap.isNull()) {
if (QMenu *menu = qobject_cast<QMenu *>(option->styleObject)) {
if (!menu->geometry().contains(QCursor::pos()))
return;
break;
}
painter->drawPixmap(shadow, shadow_pixmap);
}
} while (false);

{ // 无论如何都尝试绘制,因为可能有动画存在
color = option->palette.highlight();

QWidget *animationTargetWidget = qobject_cast<QWidget*>(option->styleObject);
if (!option->styleObject)
animationTargetWidget = dynamic_cast<QWidget*>(painter->device());

ChameleonMovementAnimation *animation = nullptr;

if (animationTargetWidget) {
animation = animationTargetWidget->findChild<ChameleonMovementAnimation*>("_d_menu_select_animation",
Qt::FindDirectChildrenOnly);
if (!animation) {
animation = new ChameleonMovementAnimation(animationTargetWidget);
animation->setObjectName("_d_menu_select_animation");
}

if (selected)
animation->setTargetRect(option->rect);
}

if (animation && animation->isRuning()) {
auto opacity = painter->opacity();
// 一些状态为 disable 的 menu item 在绘制时会修改不透明度,这里暂时改回1.0。
painter->setOpacity(1.0);
painter->fillRect(animation->currentRect(), color);
painter->setOpacity(opacity);

return animation;
} else if (selected) {
painter->fillRect(option->rect, color);
}
}

return nullptr;
}

void ChameleonStyle::drawMenuItemRedPoint(const QStyleOptionMenuItem *option, QPainter *painter, const QWidget *widget) const
Expand Down Expand Up @@ -2955,7 +3131,7 @@ bool ChameleonStyle::drawMenuItem(const QStyleOptionMenuItem *option, QPainter *
bool sunken = menuItem->state & State_Sunken;

//绘制背景
drawMenuItemBackground(option, painter, menuItem->menuItemType);
auto animation = drawMenuItemBackground(option, painter, menuItem->menuItemType);

//绘制分段
if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
Expand All @@ -2972,6 +3148,13 @@ bool ChameleonStyle::drawMenuItem(const QStyleOptionMenuItem *option, QPainter *
return true;
}

const bool useHighlightedText = selected && !animation;
if (!useHighlightedText && selected) {
// 在动画中时,selected item 的文字颜色不会使用 HighlightedText,当动画结束后会立即
// 变为 HighlightedText,会显得比较突然,因此使用不透明度对文本等内容进行过渡
painter->setOpacity(1.0 - animation->progress());
}

//绘制选择框
bool ignoreCheckMark = false;

Check warning on line 3159 in styleplugins/chameleon/chameleonstyle.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Condition '!ignoreCheckMark' is always true

Expand All @@ -2990,7 +3173,7 @@ bool ChameleonStyle::drawMenuItem(const QStyleOptionMenuItem *option, QPainter *
checkRect.moveCenter(QPoint(checkRect.left() + smallIconSize / 2, menuItem->rect.center().y()));
painter->setRenderHint(QPainter::Antialiasing);

if (selected)
if (useHighlightedText)
painter->setPen(getColor(option, QPalette::HighlightedText));
else
painter->setPen(getColor(option, QPalette::BrightText));
Expand All @@ -3010,7 +3193,7 @@ bool ChameleonStyle::drawMenuItem(const QStyleOptionMenuItem *option, QPainter *

}

if (selected) {
if (useHighlightedText) {
painter->setPen(getColor(option, QPalette::HighlightedText));
} else {
if ((option->state & QStyle::State_Enabled)) {
Expand Down Expand Up @@ -4266,6 +4449,17 @@ void ChameleonStyle::resetAttribute(QWidget *w, bool polish)
scrollbar->setProperty("_d_dtk_scrollbar_visible", true);
scrollbar->setAttribute(Qt::WA_OpaquePaintEvent, !polish);
}

if (auto progressBar = qobject_cast<QProgressBar *>(w)) {
m_progressAni.insert(progressBar, new QVariantAnimation(progressBar));
connect(m_progressAni.value(progressBar), &QVariantAnimation::valueChanged, progressBar, [progressBar](){
progressBar->update();
});

connect(progressBar, &QObject::destroyed, this, [this]() {
m_progressAni.clear();
});
}
}

static void updateWeekendTextFormat(QCalendarWidget *calendar, QColor)
Expand Down
Loading

0 comments on commit a470a53

Please sign in to comment.