mirror of https://github.com/qt/qtbase.git
QWidgetBaselineTest: Add QStyle widget baseline test
Change-Id: I2858baccb09ebf336ab7c2cde7efeb09aca6ef53 Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
parent
3a3024e6ea
commit
d23da67304
|
@ -8,4 +8,5 @@ if(TARGET Qt::Network AND TARGET Qt::Widgets)
|
|||
add_subdirectory(widgets)
|
||||
add_subdirectory(stylesheet)
|
||||
add_subdirectory(text)
|
||||
add_subdirectory(styles)
|
||||
endif()
|
||||
|
|
|
@ -28,7 +28,7 @@ protected:
|
|||
virtual void doInit() {}
|
||||
virtual void doCleanup() {}
|
||||
|
||||
private slots:
|
||||
protected slots:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (C) 2025 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(tst_baseline_styles LANGUAGES CXX)
|
||||
find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
|
||||
endif()
|
||||
|
||||
qt_internal_add_test(tst_baseline_styles
|
||||
SOURCES
|
||||
../shared/baselineprotocol.cpp ../shared/baselineprotocol.h ../shared/lookup3.cpp
|
||||
../shared/qbaselinetest.cpp ../shared/qbaselinetest.h
|
||||
../shared/qwidgetbaselinetest.cpp ../shared/qwidgetbaselinetest.h
|
||||
tst_baseline_styles.cpp
|
||||
INCLUDE_DIRECTORIES
|
||||
../shared
|
||||
LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::Widgets
|
||||
Qt::WidgetsPrivate
|
||||
Qt::Network
|
||||
)
|
|
@ -0,0 +1,266 @@
|
|||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <qbaselinetest.h>
|
||||
#include <qwidgetbaselinetest.h>
|
||||
#include <QtWidgets>
|
||||
|
||||
class tst_QStyles : public QWidgetBaselineTest
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QStyles() = default;
|
||||
|
||||
private slots:
|
||||
void initTestCase_data();
|
||||
|
||||
void drawPrimitive_data();
|
||||
void drawPrimitive();
|
||||
|
||||
void drawControl_data();
|
||||
void drawControl();
|
||||
|
||||
void drawComplexControl_data();
|
||||
void drawComplexControl();
|
||||
|
||||
private:
|
||||
void doInit() override;
|
||||
|
||||
template <typename E>
|
||||
void addData();
|
||||
|
||||
template <typename Func, typename StyleOption>
|
||||
void testStyle(Func&& func, StyleOption *styleOption, const char *name);
|
||||
};
|
||||
|
||||
#define QBASELINE_CHECK_STYLE(name) \
|
||||
testStyle([&](auto *style, auto *styleOption, auto *painter, QWidget *widget) { \
|
||||
(style->*drawFunction)(styleElement, styleOption, painter, widget); \
|
||||
}, styleOption.get(), name);
|
||||
|
||||
void tst_QStyles::initTestCase_data()
|
||||
{
|
||||
// FIXME: Check all styles via global data when baseline tests support global tags
|
||||
}
|
||||
|
||||
void tst_QStyles::doInit()
|
||||
{
|
||||
testWindow()->resize(140, 140);
|
||||
}
|
||||
|
||||
void tst_QStyles::drawPrimitive_data()
|
||||
{
|
||||
addData<QStyle::PrimitiveElement>();
|
||||
}
|
||||
|
||||
QStyleOption *styleOptionFor(QStyle::PrimitiveElement element)
|
||||
{
|
||||
switch (element) {
|
||||
case QStyle::PE_FrameTabBarBase:
|
||||
return new QStyleOptionTabBarBase();
|
||||
case QStyle::PE_IndicatorHeaderArrow:
|
||||
return new QStyleOptionHeader();
|
||||
case QStyle::PE_IndicatorCheckBox:
|
||||
case QStyle::PE_PanelButtonCommand:
|
||||
return new QStyleOptionFocusRect();
|
||||
case QStyle::PE_FrameFocusRect:
|
||||
return new QStyleOptionFocusRect();
|
||||
case QStyle::PE_Frame:
|
||||
case QStyle::PE_FrameMenu:
|
||||
case QStyle::PE_PanelMenuBar:
|
||||
case QStyle::PE_FrameGroupBox:
|
||||
case QStyle::PE_FrameDockWidget:
|
||||
case QStyle::PE_PanelLineEdit:
|
||||
case QStyle::PE_FrameLineEdit:
|
||||
case QStyle::PE_FrameWindow:
|
||||
case QStyle::PE_FrameButtonBevel:
|
||||
case QStyle::PE_FrameButtonTool:
|
||||
return new QStyleOptionFrame();
|
||||
case QStyle::PE_FrameTabWidget:
|
||||
return new QStyleOptionTabWidgetFrame();
|
||||
case QStyle::PE_IndicatorTabTear:
|
||||
return new QStyleOptionTab();
|
||||
case QStyle::PE_IndicatorColumnViewArrow:
|
||||
case QStyle::PE_PanelItemViewRow:
|
||||
case QStyle::PE_PanelItemViewItem:
|
||||
case QStyle::PE_IndicatorItemViewItemCheck:
|
||||
return new QStyleOptionViewItem();
|
||||
default:
|
||||
return new QStyleOption();
|
||||
};
|
||||
}
|
||||
|
||||
void tst_QStyles::drawPrimitive()
|
||||
{
|
||||
QFETCH(QStyle::PrimitiveElement, styleElement);
|
||||
|
||||
auto drawFunction = &QStyle::drawPrimitive;
|
||||
|
||||
std::unique_ptr<QStyleOption> styleOption(styleOptionFor(styleElement));
|
||||
styleOption->initFrom(testWindow());
|
||||
QBASELINE_CHECK_STYLE("default");
|
||||
|
||||
if (auto *headerOption = qstyleoption_cast<QStyleOptionHeader*>(styleOption.get())) {
|
||||
headerOption->sortIndicator = QStyleOptionHeader::SortDown;
|
||||
QBASELINE_CHECK_STYLE("down");
|
||||
|
||||
headerOption->sortIndicator = QStyleOptionHeader::SortUp;
|
||||
QBASELINE_CHECK_STYLE("up");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QStyles::drawControl_data()
|
||||
{
|
||||
addData<QStyle::ControlElement>();
|
||||
}
|
||||
|
||||
QStyleOption *styleOptionFor(QStyle::ControlElement element)
|
||||
{
|
||||
switch (element) {
|
||||
case QStyle::CE_PushButton:
|
||||
case QStyle::CE_PushButtonBevel:
|
||||
case QStyle::CE_PushButtonLabel:
|
||||
case QStyle::CE_RadioButton:
|
||||
case QStyle::CE_RadioButtonLabel:
|
||||
case QStyle::CE_CheckBox:
|
||||
case QStyle::CE_CheckBoxLabel: {
|
||||
auto *buttonStyle = new QStyleOptionButton;
|
||||
buttonStyle->text = QString("Hello");
|
||||
return buttonStyle;
|
||||
}
|
||||
case QStyle::CE_MenuBarItem:
|
||||
return new QStyleOptionMenuItem;
|
||||
case QStyle::CE_ProgressBar:
|
||||
case QStyle::CE_ProgressBarLabel:
|
||||
case QStyle::CE_ProgressBarContents:
|
||||
return new QStyleOptionProgressBar;
|
||||
case QStyle::CE_Header:
|
||||
case QStyle::CE_HeaderLabel:
|
||||
case QStyle::CE_HeaderSection:
|
||||
return new QStyleOptionHeader;
|
||||
case QStyle::CE_ToolButtonLabel:
|
||||
return new QStyleOptionToolButton;
|
||||
case QStyle::CE_ToolBoxTab:
|
||||
case QStyle::CE_ToolBoxTabShape:
|
||||
case QStyle::CE_ToolBoxTabLabel:
|
||||
return new QStyleOptionToolBox;
|
||||
case QStyle::CE_TabBarTab:
|
||||
case QStyle::CE_TabBarTabShape:
|
||||
case QStyle::CE_TabBarTabLabel:
|
||||
return new QStyleOptionTab;
|
||||
case QStyle::CE_RubberBand:
|
||||
return new QStyleOptionRubberBand;
|
||||
case QStyle::CE_DockWidgetTitle:
|
||||
return new QStyleOptionDockWidget;
|
||||
case QStyle::CE_ComboBoxLabel:
|
||||
return new QStyleOptionComboBox;
|
||||
case QStyle::CE_ToolBar:
|
||||
return new QStyleOptionToolBar;
|
||||
case QStyle::CE_ItemViewItem:
|
||||
return new QStyleOptionViewItem;
|
||||
case QStyle::CE_ShapedFrame:
|
||||
return new QStyleOptionFrame;
|
||||
default:
|
||||
return new QStyleOption;
|
||||
};
|
||||
}
|
||||
|
||||
void tst_QStyles::drawControl()
|
||||
{
|
||||
QFETCH(QStyle::ControlElement, styleElement);
|
||||
|
||||
auto drawFunction = &QStyle::drawControl;
|
||||
|
||||
std::unique_ptr<QStyleOption> styleOption(styleOptionFor(styleElement));
|
||||
styleOption->state = QStyle::State_Active
|
||||
| QStyle::State_Enabled
|
||||
| QStyle::State_HasFocus
|
||||
| QStyle::State_On;
|
||||
|
||||
QBASELINE_CHECK_STYLE("default");
|
||||
}
|
||||
|
||||
void tst_QStyles::drawComplexControl_data()
|
||||
{
|
||||
addData<QStyle::ComplexControl>();
|
||||
}
|
||||
|
||||
QStyleOptionComplex *styleOptionFor(QStyle::ComplexControl element)
|
||||
{
|
||||
switch (element) {
|
||||
case QStyle::CC_Slider:
|
||||
case QStyle::CC_ScrollBar:
|
||||
return new QStyleOptionSlider();
|
||||
case QStyle::CC_ToolButton:
|
||||
return new QStyleOptionToolButton();
|
||||
case QStyle::CC_SpinBox:
|
||||
return new QStyleOptionSpinBox();
|
||||
case QStyle::CC_TitleBar:
|
||||
return new QStyleOptionTitleBar();
|
||||
case QStyle::CC_ComboBox:
|
||||
return new QStyleOptionComboBox();
|
||||
case QStyle::CC_GroupBox:
|
||||
return new QStyleOptionGroupBox();
|
||||
default:
|
||||
return new QStyleOptionComplex();
|
||||
};
|
||||
}
|
||||
|
||||
void tst_QStyles::drawComplexControl()
|
||||
{
|
||||
QFETCH(QStyle::ComplexControl, styleElement);
|
||||
|
||||
auto drawFunction = &QStyle::drawComplexControl;
|
||||
|
||||
std::unique_ptr<QStyleOptionComplex> styleOption(styleOptionFor(styleElement));
|
||||
styleOption->initFrom(testWindow());
|
||||
styleOption->subControls = QStyle::SC_All;
|
||||
|
||||
QBASELINE_CHECK_STYLE("default");
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void tst_QStyles::addData()
|
||||
{
|
||||
auto metaEnum = QMetaEnum::fromType<E>();
|
||||
QTest::addColumn<E>("styleElement");
|
||||
|
||||
for (int i = 0; i < metaEnum.keyCount() - 1; ++i) {
|
||||
auto value = E(metaEnum.value(i));
|
||||
QTest::newRow(metaEnum.key(i)) << value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func, typename StyleOption>
|
||||
void tst_QStyles::testStyle(Func&& drawFunc, StyleOption *styleOption, const char *name)
|
||||
{
|
||||
QStyle *style = qApp->style();
|
||||
QWidget *w = testWindow();
|
||||
|
||||
const auto dpr = w->devicePixelRatio();
|
||||
const auto size = w->size();
|
||||
|
||||
QImage image(size * dpr, QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(dpr);
|
||||
QPainter painter(&image);
|
||||
|
||||
QBrush checkerboardBackground = w->parentWidget()->palette().brush(QPalette::Window);
|
||||
painter.fillRect(QRect({}, size), checkerboardBackground);
|
||||
|
||||
styleOption->rect = w->rect() -= QMargins(20, 20, 20, 20);
|
||||
|
||||
drawFunc(style, styleOption, &painter, w);
|
||||
painter.end();
|
||||
|
||||
if (!debugRects.isEmpty()) {
|
||||
QJsonDocument doc(debugRects);
|
||||
image.setText("DebugRects", doc.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
QBASELINE_CHECK(image, name);
|
||||
}
|
||||
|
||||
QBASELINETEST_MAIN(tst_QStyles)
|
||||
|
||||
#include "tst_baseline_styles.moc"
|
Loading…
Reference in New Issue