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#231
  • Loading branch information
deepin-ci-robot committed Jul 9, 2024
1 parent b049bf8 commit b16b768
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 73 deletions.
21 changes: 16 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,23 @@ function(dtk_add_plugin)
endfunction()

find_package(Dtk${VERSION_SUFFIX} REQUIRED COMPONENTS Widget)
cmake_dependent_option(ENABLE_QT_XDG_ICON_LOADER "Enable QtXdgIconLoader" ON "QT_VERSION_MAJOR EQUAL 5" OFF)

option(ENABLE_QT_XDG_ICON_LOADER "Enable QtXdgIconLoader" ON)
find_package(Qt${QT_VERSION_MAJOR}XdgIconLoader)
find_package(Qt${QT_VERSION_MAJOR}Xdg REQUIRED)
if (NOT Qt${QT_VERSION_MAJOR}XdgIconLoader_FOUND)
message(WARNING " Qt${QT_VERSION_MAJOR}XdgIconLoader Not Found, DISABLE QtXdgIconLoader !")
set (ENABLE_QT_XDG_ICON_LOADER OFF)
endif()

if(ENABLE_QT_XDG_ICON_LOADER)
find_package(Qt5XdgIconLoader REQUIRED)
find_package(Qt5Xdg REQUIRED)
set(QT_XDG_ICON_DEPS Qt5XdgIconLoader Qt5Xdg)
set(XDG_ICON_VERSION_MAJOR ${Qt5XdgIconLoader_VERSION_MAJOR})
set(QT_XDG_ICON_DEPS Qt${QT_VERSION_MAJOR}XdgIconLoader Qt${QT_VERSION_MAJOR}Xdg)

if("${QT_VERSION_MAJOR}" STREQUAL "5")
set(XDG_ICON_VERSION_MAJOR ${Qt5XdgIconLoader_VERSION_MAJOR})
elseif("${QT_VERSION_MAJOR}" STREQUAL "6")
set(XDG_ICON_VERSION_MAJOR ${Qt6XdgIconLoader_VERSION_MAJOR})
endif()
endif()

set(PLUGIN_OUTPUT_BASE_DIR ${CMAKE_BINARY_DIR}/plugins CACHE STRING "Plugin output base path")
Expand Down
4 changes: 3 additions & 1 deletion platformthemeplugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus Widgets)
set(QT_LIBS Qt${QT_VERSION_MAJOR}::DBus Qt${QT_VERSION_MAJOR}::Widgets)
if(QT_VERSION_MAJOR EQUAL 5)
find_package(Qt5X11Extras REQUIRED)
list(APPEND QT_LIBS Qt5::X11Extras ${QT_XDG_ICON_DEPS})
list(APPEND QT_LIBS Qt5::X11Extras)
if(QT_VERSION_MINOR GREATER_EQUAL 8) # Qt5.8
find_package(Qt5ThemeSupport REQUIRED)
list(APPEND QT_LIBS Qt5::ThemeSupportPrivate)
Expand All @@ -26,10 +26,12 @@ if(QT_VERSION_MAJOR EQUAL 5)
else()
list(APPEND QT_LIBS Qt6::GuiPrivate)
endif()

find_package(PkgConfig REQUIRED)
pkg_check_modules(Deps REQUIRED IMPORTED_TARGET mtdev x11)
if(ENABLE_QT_XDG_ICON_LOADER)
set(DEFS -DXDG_ICON_VERSION_MAR=${XDG_ICON_VERSION_MAJOR})
list(APPEND QT_LIBS ${QT_XDG_ICON_DEPS})
endif()
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_dbus_interface(DBUS_INTERFACES ${CMAKE_CURRENT_LIST_DIR}/xmls/com.deepin.filemanager.filedialog.xml filedialog_interface)
Expand Down
168 changes: 102 additions & 66 deletions styleplugins/chameleon/chameleonstyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <QBitmap>
#include <QTableView>
#include <QStyledItemDelegate>
#include <QVariantAnimation>
#include <DSpinBox>
#include <DTreeView>
#include <DIconButton>
Expand Down Expand Up @@ -122,6 +123,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 @@ -2757,7 +2809,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,50 +2818,11 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
painter->setPen(Qt::NoPen);
painter->setBrush(getColor(option, QPalette::Highlight));
painter->drawRect(option->rect);
return;
return nullptr;
}

// 清理旧的阴影
if (option->styleObject) {
const QRect shadow = option->styleObject->property("_d_menu_shadow_rect").toRect();
const QRect shadow_base = option->styleObject->property("_d_menu_shadow_base_rect").toRect();

// 如果当前菜单项时已选中的,并且shadow_base不等于当前区域,此时应当清理阴影区域
// 如果当前要绘制的item是触发阴影绘制的那一项,那么,此时应当清空阴影区域
if ((selected && shadow_base != option->rect)
|| (!selected && shadow_base == option->rect)
|| (!selected && shadow_base.width() != option->rect.width())) {
// 清空阴影区域
option->styleObject->setProperty("_d_menu_shadow_rect", QVariant());
option->styleObject->setProperty("_d_menu_shadow_base_rect", QVariant());

// 确保阴影区域能重绘
if (QWidget *w = qobject_cast<QWidget*>(option->styleObject)) {
w->update(shadow);
}
}
}

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

// draw shadow
if (type == QStyleOptionMenuItem::Normal) {
if (option->styleObject) {
QRect shadow(0, 0, option->rect.width(), 7);
shadow.moveTop(option->rect.bottom() + 1);
option->styleObject->setProperty("_d_menu_shadow_rect", shadow);
option->styleObject->setProperty("_d_menu_shadow_base_rect", option->rect);

// 确保阴影区域能重绘
if (QWidget *w = qobject_cast<QWidget*>(option->styleObject)) {
w->update(shadow);
}
}
}

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,35 +2859,51 @@ void ChameleonStyle::drawMenuItemBackground(const QStyleOption *option, QPainter
}

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

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

// 判断阴影rect是否在自己的区域
if (!option->rect.contains(shadow.center()))
return;
{ // 无论如何都尝试绘制,因为可能有动画存在
color = option->palette.highlight();

static QColor shadow_color;
static QPixmap shadow_pixmap;
QWidget *animationTargetWidget = qobject_cast<QWidget*>(option->styleObject);
if (!option->styleObject)
animationTargetWidget = dynamic_cast<QWidget*>(painter->device());

if (shadow_color != option->palette.color(QPalette::Active, QPalette::Highlight)) {
shadow_color = option->palette.color(QPalette::Active, QPalette::Highlight);
QImage image(":/chameleonstyle/menu_shadow.svg");
QPainter pa(&image);
pa.setCompositionMode(QPainter::CompositionMode_SourceIn);
pa.fillRect(image.rect(), shadow_color);
shadow_pixmap = QPixmap::fromImage(image);
}
ChameleonMovementAnimation *animation = nullptr;

if (!shadow_pixmap.isNull()) {
if (QMenu *menu = qobject_cast<QMenu *>(option->styleObject)) {
if (!menu->geometry().contains(QCursor::pos()))
return;
if (animationTargetWidget) {
animation = animationTargetWidget->findChild<ChameleonMovementAnimation*>("_d_menu_select_animation",
Qt::FindDirectChildrenOnly);
if (!animation) {
animation = new ChameleonMovementAnimation(animationTargetWidget);
animation->setObjectName("_d_menu_select_animation");
}
painter->drawPixmap(shadow, shadow_pixmap);

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

if (animation && animation->isRuning()) {
auto opacity = painter->opacity();
// 一些状态为 disable 的 menu item 在绘制时会修改不透明度,这里暂时改回1.0。
painter->setOpacity(1.0);
painter->setBrush(color);
painter->setPen(Qt::NoPen);
QRect rect = animation->currentRect().adjusted(6, 0, -6, 0);
painter->drawRoundedRect(rect, 6, 6);
painter->setOpacity(opacity);

return animation;
} else if (selected) {
painter->setBrush(color);
painter->setPen(Qt::NoPen);
QRect rect = option->rect.adjusted(6, 0, -6, 0);
painter->drawRoundedRect(rect, 6, 6);
}
}

return nullptr;
}

void ChameleonStyle::drawMenuItemRedPoint(const QStyleOptionMenuItem *option, QPainter *painter, const QWidget *widget) const
Expand Down Expand Up @@ -2955,7 +2984,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 +3001,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 3012 in styleplugins/chameleon/chameleonstyle.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Condition '!ignoreCheckMark' is always true

Expand All @@ -2990,7 +3026,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 +3046,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
30 changes: 29 additions & 1 deletion styleplugins/chameleon/chameleonstyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define CHAMELEONSTYLE_H

#include <DStyle>
#include <QVariantAnimation>

DWIDGET_USE_NAMESPACE

Expand All @@ -18,6 +19,33 @@ class DStyleOptionButtonBoxButton;
DWIDGET_END_NAMESPACE

namespace chameleon {
class ChameleonMovementAnimation : public QVariantAnimation
{
Q_OBJECT

public:
explicit ChameleonMovementAnimation(QWidget *targetWidget);

inline QRect currentRect() const {
return m_currentRect;
}

inline bool isRuning() const {
return state() == QVariantAnimation::Running;
}

inline float progress() const {
return float(currentLoopTime()) / duration();
}

QWidget *targetWidget() const;
void setTargetRect(const QRect &rect);

private:
QRect m_currentRect;
QRect m_targetRect;
QRect m_lastTargetRect;
};

class ChameleonStyle : public DStyle
{
Expand Down Expand Up @@ -67,7 +95,7 @@ class ChameleonStyle : public DStyle
bool drawSpinBox(const QStyleOptionSpinBox *opt, QPainter *p, const QWidget *w) const;
void updateSpinBoxButtonState(const QStyleOptionSpinBox *opt, QStyleOptionButton& button, bool isActive, bool isEnabled) const;
bool drawMenuBarItem(const QStyleOptionMenuItem *option, QRect &rect, QPainter *painter, const QWidget *widget) const;
void drawMenuItemBackground(const QStyleOption *option, QPainter *painter, QStyleOptionMenuItem::MenuItemType type) const;
ChameleonMovementAnimation *drawMenuItemBackground(const QStyleOption *option, QPainter *painter, QStyleOptionMenuItem::MenuItemType type) const;
bool drawMenuItem(const QStyleOptionMenuItem *option, QPainter *painter, const QWidget *widget) const;
bool drawTabBar(QPainter *painter ,const QStyleOptionTab *tab, const QWidget *widget) const;
bool drawTabBarLabel(QPainter *painter ,const QStyleOptionTab *tab, const QWidget *widget) const;
Expand Down

0 comments on commit b16b768

Please sign in to comment.