Revision control

Copy as Markdown

// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qohosstyle_p.h"
#include <QtGui/qicon.h>
#include <QtGui/qpainter.h>
#include <QtGui/qpainterpath.h>
#include <QtWidgets/qabstractscrollarea.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qcombobox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/qlistview.h>
#include <QtWidgets/qmdisubwindow.h>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qradiobutton.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qspinbox.h>
#include <QtWidgets/qstyleditemdelegate.h>
#include <QtWidgets/qstyleoption.h>
#include <QtWidgets/qtoolbutton.h>
#include <QtWidgets/qtreeview.h>
#include "qpa/qplatformtheme.h"
#include "private/qguiapplication_p.h"
#include "private/qstylehelper_p.h"
#include <algorithm>
namespace {
// Map a standard pixmap to the XDG icon-theme name that QAbstractFileIconProvider
// uses for the same QFileIconProvider type, so the widgets path resolves through the
// platform theme's icon engine exactly as the gui path does.
QString ohosThemeIconName(QStyle::StandardPixmap standardPixmap)
{
switch (standardPixmap) {
case QStyle::SP_ComputerIcon: return QStringLiteral("computer");
case QStyle::SP_DesktopIcon: return QStringLiteral("user-desktop");
case QStyle::SP_TrashIcon: return QStringLiteral("user-trash");
case QStyle::SP_DriveNetIcon: return QStringLiteral("network-workgroup");
case QStyle::SP_DriveHDIcon: return QStringLiteral("drive-harddisk");
case QStyle::SP_DirClosedIcon: return QStringLiteral("folder");
case QStyle::SP_DirIcon: return QStringLiteral("folder");
case QStyle::SP_FileIcon: return QStringLiteral("text-x-generic");
default: break;
}
return QString();
}
constexpr int checkBoxOrRadioButtonIndicatorSize = 24;
constexpr int checkBoxOrRadioButtonIndicatorStrokeWidth = 1;
constexpr int checkBoxOrRadioButtonIndicatorGap = 2;
constexpr int checkBoxOrRadioButtonHoverSize =
checkBoxOrRadioButtonIndicatorSize + (2 * checkBoxOrRadioButtonIndicatorGap);
constexpr int checkBoxOrRadioButtonFocusStrokeWidth = 2;
constexpr int checkBoxOrRadioButtonSize =
checkBoxOrRadioButtonIndicatorSize + (2 * checkBoxOrRadioButtonIndicatorGap)
+ (2 * checkBoxOrRadioButtonFocusStrokeWidth);
constexpr int radioButtonIndicatorStrokeWidth = 6;
constexpr int textCursorWidth = 1;
constexpr int itemViewItemHorizontalMargin = 16;
constexpr int itemViewItemVerticalMargin = 8;
constexpr int itemViewItemWithDecorationVerticalMargin = 10;
constexpr int itemViewItemSpacing = 8;
constexpr int itemViewSeparatorHeight = 5;
constexpr int focusFrameWidth = 2;
constexpr int focusFrameCornerRadius = 16;
constexpr int headerMargin = 16;
constexpr int headerDefaultSectionSizeVertical = 48;
constexpr double lineEditCornerRadius = 32.0;
constexpr int lineEditHorizontalMargin = 16;
constexpr int lineEditVerticalMargin = 9;
constexpr int menuBarItemSpacing = 16;
constexpr int menuBarVerticalMargin = 8;
constexpr int menuBarHorizontalMargin = 8;
constexpr int menuItemVerticalMargin = 8;
constexpr int menuItemCornerRadius = 4;
constexpr int menuItemHoverHorizontalMargin = 4;
constexpr int pushButtonHorizontalMargin = 16;
constexpr int pushButtonVerticalMargin = 8;
constexpr int pushButtonCornerRadius = 8;
constexpr int pushButtonFocusFrameGap = 2;
constexpr int pushButtonFocusFrameWidth = 2;
constexpr int progressBarMinHeight = 24;
constexpr int progressBarGrooveHeight = 4;
constexpr int progressBarCornerRadius = 2;
constexpr int shadowXSRadius = 22;
constexpr int sliderThickness = 40;
constexpr int sliderGrooveHeight = 4;
constexpr int sliderCornerRadius = 2;
constexpr int sliderThumbSize = 16;
constexpr int sliderHoverSize = 4;
constexpr int sliderFocusStrokeWidth = 2;
constexpr int smallIconSize = 12;
constexpr int splitterHandleWidth = 6;
constexpr int splitterWidth = 12;
constexpr int titleBarHeight = 46;
constexpr int toolButtonCornerRadius = 4;
constexpr int toolButtonFocusFrameWidth = 2;
constexpr int toolTipCornerRadius = 8;
constexpr int toolTipFrameWidth = 8;
constexpr int toolTipBackgroundAlpha = 204;
constexpr int spinBoxFrameHeight = 32;
constexpr int spinBoxButtonBoxWidth = 32;
constexpr int spinBoxButtonBoxHeight = 16;
constexpr int spinBoxEditHorizontalMargin = 4;
constexpr double spinBoxFrameRadius = 12.0;
constexpr int spinBoxFrameStroke = 2;
constexpr int maxScrollBarSize = 9;
constexpr int thinScrollBarSize = 3;
constexpr int thickScrollBarSize = 6;
constexpr int tabBarTabRadius = 8;
constexpr int tabBarTabFrameWidth = 2;
constexpr int tabBarTabUnderLineWidth = 2;
constexpr int groupBoxBottomPadding = 8;
constexpr int groupBoxFrameCornerRadius = 8;
constexpr int groupBoxHorizontalPadding = 12;
constexpr int groupBoxTitleToContentSpacing = 8;
constexpr int groupBoxTopPadding = 24;
constexpr int comboBoxVerticalMargin = 4;
constexpr int comboBoxFrameRadius = 8;
constexpr int comboBoxFrameLeftRightPadding = 16;
constexpr int comboBoxFocusFrameWidth = 2;
constexpr int tabWidgetFrameWidth = 1;
constexpr double ohos_id_alpha_disabled = 0.4;
constexpr double ohos_id_alpha_content_tertiary = 0.4;
QColor makeInactiveOrDisabledFromColor(const QColor &color)
{
auto disabledColor = color;
disabledColor.setAlphaF(qBound(0.0, color.alphaF() * ohos_id_alpha_disabled, 1.0));
return disabledColor;
}
template<typename T>
bool qobjectIsInstanceOf(const QObject *obj)
{
return qobject_cast<const T *>(obj) != nullptr;
}
template<typename T>
bool qStyleOptionIs(const QStyleOption *option)
{
return qstyleoption_cast<const T *>(option) != nullptr;
}
bool isItemViewSeparator(const QModelIndex &index)
{
return index.data(Qt::AccessibleDescriptionRole).toString() == QLatin1String("separator");
}
bool isFirstItem(const QModelIndex &index)
{
return index.isValid() && index.row() == 0 && index.column() == 0;
}
bool isLastItem(const QModelIndex &index)
{
return index.isValid()
&& index.row() == index.model()->rowCount(index.parent()) - 1
&& index.column() == index.model()->columnCount(index.parent()) - 1;
}
bool isHoverable(const QWidget *widget)
{
static bool (* const hoverTypeCheckFuncs[])(const QObject *obj) = {
&qobjectIsInstanceOf<QCheckBox>,
&qobjectIsInstanceOf<QPushButton>,
&qobjectIsInstanceOf<QRadioButton>,
&qobjectIsInstanceOf<QSlider>,
&qobjectIsInstanceOf<QToolButton>,
&qobjectIsInstanceOf<QComboBox>,
&qobjectIsInstanceOf<QScrollBar>,
};
return std::any_of(
std::begin(hoverTypeCheckFuncs), std::end(hoverTypeCheckFuncs),
[&](const auto &typeCheckFunc) {
return typeCheckFunc(widget);
});
}
QRect adjusted(const QRect &rect, int growth)
{
return rect.adjusted(-growth, -growth, growth, growth);
}
QFont getGroupBoxTitleFont(const QWidget *widget)
{
const bool widgetHasItsOwnFont = widget != nullptr && widget->testAttribute(Qt::WA_SetFont);
if (widgetHasItsOwnFont)
return widget->font();
const auto *themeFont =
QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::GroupBoxTitleFont);
return themeFont != nullptr ? *themeFont : QFont();
}
QColor getSunkenOrHoverColor(bool isSunken, const QPalette &palette)
{
return isSunken
? palette.color(QPalette::Active, QPalette::Dark)
: palette.color(QPalette::Active, QPalette::Light);
}
void paintOnStackTop(QPainter &painter, const std::function<void(QPainter &painter)> &paint)
{
painter.save();
paint(painter);
painter.restore();
}
void drawLine(QPainter &painter, const QPen &pen, const QPoint &aPoint, const QPoint &bPoint)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(pen);
painter.drawLine(aPoint, bPoint);
});
}
void drawEllipse(QPainter &painter, const QPen &pen, const QBrush &brush, const QRect &rect)
{
painter.save();
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawEllipse(rect);
painter.restore();
}
void drawRect(QPainter &painter, const QPen &pen, const QBrush &brush, const QRect &rect)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawRect(rect);
});
}
void drawRoundedRect(
QPainter &painter, const QPen &pen, const QBrush &brush, const QRectF &rect, qreal xRadius, qreal yRadius)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawRoundedRect(rect, xRadius, yRadius);
});
}
QPainterPath roundedPathInRect(
const QRectF &rect, qreal topLeftCornerRadius, qreal topRightCornerRadius, qreal bottomLeftCornerRadius,
qreal bottomRightCornerRadius)
{
QPainterPath path;
const auto bottom = rect.y() + rect.height();
const auto right = rect.x() + rect.width();
const auto topLeftDiameter = 2 * topLeftCornerRadius;
path.moveTo(rect.x() + topLeftCornerRadius, rect.y());
path.arcTo(rect.x(), rect.y(), topLeftDiameter, topLeftDiameter, 90.0, 90.0);
const auto bottomLeftDiameter = 2 * bottomLeftCornerRadius;
path.lineTo(rect.x(), bottom - bottomLeftCornerRadius);
path.arcTo(rect.x(), bottom - bottomLeftDiameter, bottomLeftDiameter, bottomLeftDiameter, 180.0, 90.0);
const auto bottomRightDiameter = 2 * bottomRightCornerRadius;
path.lineTo(right - bottomRightCornerRadius, bottom);
path.arcTo(
right - bottomRightDiameter, bottom - bottomRightDiameter, bottomRightDiameter, bottomRightDiameter, 270.0,
90.0);
const auto topRightDiameter = 2 * topRightCornerRadius;
path.lineTo(right, rect.y() + topRightCornerRadius);
path.arcTo(right - topRightDiameter, rect.y(), topRightDiameter, topRightDiameter, 360.0, 90.0);
path.closeSubpath();
return path;
}
void drawPath(QPainter &painter, const QPen &pen, const QBrush &brush, const QPainterPath& path)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(pen);
painter.setBrush(brush);
painter.drawPath(path);
});
}
void drawRoundedRect(
QPainter &painter, const QPen &pen, const QBrush brush, const QRectF &rect, qreal topLeftCornerRadius,
qreal topRightCornerRadius, qreal bottomLeftCornerRadius, qreal bottomRightCornerRadius)
{
drawPath(
painter, pen, brush, roundedPathInRect(rect, topLeftCornerRadius, topRightCornerRadius, bottomLeftCornerRadius,
bottomRightCornerRadius));
}
void drawPolyline(
QPainter &painter, const QPen &pen, const QBrush &brush, const std::vector<QPointF> &polygonPoints)
{
paintOnStackTop(painter, [&](auto &p) {
p.setRenderHint(QPainter::Antialiasing);
p.setPen(pen);
p.setBrush(brush);
p.drawPolyline(polygonPoints.data(), polygonPoints.size());
});
}
enum class ArrowDirection { Up, Down, Left, Right };
void drawArrow(
QPainter &painter, const QRectF &boundingRect, qreal arrowSize, ArrowDirection direction,
const QColor &color)
{
const auto arrowWidth = 2;
const auto arrowCenter = boundingRect.center();
auto arrowRect = QRectF(0, 0, arrowSize, arrowSize * 0.5);
arrowRect.moveCenter(arrowCenter);
arrowRect.adjust(arrowWidth * 0.5, arrowWidth * 0.5, -arrowWidth * 0.5, -arrowWidth * 0.5);
const std::vector<QPointF> polygonPoints = {
QPointF(arrowRect.x(), arrowRect.y()),
QPointF(arrowRect.x() + arrowRect.width() * 0.5, arrowRect.y() + arrowRect.height()),
QPointF(arrowRect.x() + arrowRect.width(), arrowRect.y())
};
paintOnStackTop(painter, [&](auto &p) {
p.translate(arrowCenter);
switch (direction) {
case ArrowDirection::Down:
break;
case ArrowDirection::Up:
p.rotate(180);
break;
case ArrowDirection::Left:
p.rotate(90);
break;
case ArrowDirection::Right:
p.rotate(-90);
break;
}
p.translate(-arrowCenter);
drawPolyline(
p, QPen(color, arrowWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin), Qt::NoBrush,
polygonPoints);
});
}
void drawCheckBoxOrRadioButtonIndicator(QPainter &painter, const QStyleOption &option, bool isCheckBox)
{
const auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
const auto isOn = option.state.testFlag(QStyle::State_On);
const auto isMouseOver = option.state.testFlag(QStyle::State_MouseOver);
const auto isSunken = option.state.testFlag(QStyle::State_Sunken);
painter.save();
painter.setRenderHints(QPainter::Antialiasing);
painter.setOpacity(isEnabled ? 1.0 : ohos_id_alpha_disabled);
QRect hoverRect(0, 0, checkBoxOrRadioButtonHoverSize, checkBoxOrRadioButtonHoverSize);
hoverRect.moveCenter(option.rect.center());
if (isMouseOver || isSunken)
drawEllipse(painter, Qt::NoPen, getSunkenOrHoverColor(isSunken, option.palette), hoverRect);
QRect indicatorRect(0, 0, checkBoxOrRadioButtonIndicatorSize, checkBoxOrRadioButtonIndicatorSize);
indicatorRect.moveCenter(option.rect.center());
auto activeColor = option.palette.color(QPalette::Active, QPalette::Highlight);
if (isOn) {
if (isCheckBox) {
drawEllipse(painter, Qt::NoPen, activeColor, indicatorRect);
QPixmap svgPixmap(indicatorRect.size());
if (svgPixmap.load(QString::fromStdString(":/resources/ic_gallery_material_select_checkbo.svg"))) {
painter.drawPixmap(indicatorRect.topLeft(), svgPixmap);
}
} else {
drawEllipse(
painter, QPen(activeColor, radioButtonIndicatorStrokeWidth), Qt::NoBrush,
adjusted(indicatorRect, -radioButtonIndicatorStrokeWidth / 2));
}
} else {
const auto outlineColor = option.palette.color(QPalette::Inactive, QPalette::Button);
const auto backgroundBrush = option.palette.brush(QPalette::Inactive, QPalette::Base);
const auto discRect = adjusted(indicatorRect, -checkBoxOrRadioButtonIndicatorStrokeWidth);
drawEllipse(
painter, QPen(outlineColor, checkBoxOrRadioButtonIndicatorStrokeWidth), backgroundBrush,
discRect);
if (const auto *themePalette = QGuiApplicationPrivate::platformTheme()->palette(
isCheckBox
? QPlatformTheme::Palette::CheckBoxPalette
: QPlatformTheme::Palette::RadioButtonPalette)) {
const auto overlayOutlineColor = themePalette->color(QPalette::Inactive, QPalette::Button);
const auto overlayBackgroundBrush = themePalette->brush(QPalette::Inactive, QPalette::Base);
const bool shouldPresentOverlayForOverriddenOutlineColor =
outlineColor != overlayOutlineColor;
const bool shouldPresentOverlayForOverriddenBackgroundBrush =
backgroundBrush != overlayBackgroundBrush;
if (shouldPresentOverlayForOverriddenOutlineColor
|| shouldPresentOverlayForOverriddenBackgroundBrush) {
drawEllipse(
painter,
shouldPresentOverlayForOverriddenOutlineColor
? QPen(overlayOutlineColor, checkBoxOrRadioButtonIndicatorStrokeWidth)
: QPen(Qt::NoPen),
shouldPresentOverlayForOverriddenBackgroundBrush
? overlayBackgroundBrush
: QBrush(Qt::NoBrush),
discRect);
}
}
}
painter.restore();
}
void drawLineEditBackground(QPainter &painter, const QStyleOption &option)
{
auto radius = std::min(
std::min(option.rect.size().width(), option.rect.size().height()) * 0.5, lineEditCornerRadius);
const auto colorGroup = option.palette.currentColorGroup();
const auto baseBrush = option.palette.brush(colorGroup, QPalette::Base);
drawRoundedRect(painter, Qt::NoPen, baseBrush, option.rect, radius, radius);
if (const auto *ohosThemePalette = QGuiApplicationPrivate::platformTheme()->palette(
QPlatformTheme::Palette::TextLineEditPalette)) {
const auto overlayBaseBrush = ohosThemePalette->brush(colorGroup, QPalette::Base);
const bool shouldPresentOverlayForOverriddenBaseBrush = baseBrush != overlayBaseBrush;
if (shouldPresentOverlayForOverriddenBaseBrush)
drawRoundedRect(painter, Qt::NoPen, overlayBaseBrush, option.rect, radius, radius);
}
}
QColor getPushButtonOverlayFill(bool isPressed, const QStyleOptionButton &option)
{
const auto role = isPressed ? QPalette::Dark : QPalette::Light;
if (const auto *themePalette =
QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::Palette::ButtonPalette))
return themePalette->color(QPalette::Active, role);
return option.palette.color(QPalette::Active, role);
}
QBrush getPushButtonBackgroundBrush(const QStyleOptionButton &option)
{
const auto isDefaultButton = option.features.testFlag(QStyleOptionButton::DefaultButton);
const auto isAutoDefaultButton = option.features.testFlag(QStyleOptionButton::AutoDefaultButton);
const auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
const auto isOn = option.state.testFlag(QStyle::State_On);
const auto defaultButtonBackgroundColor = isEnabled
? option.palette.color(QPalette::Active, QPalette::AlternateBase)
: makeInactiveOrDisabledFromColor(option.palette.color(QPalette::Active, QPalette::AlternateBase));
if (isOn)
return isDefaultButton || isAutoDefaultButton
? defaultButtonBackgroundColor
: getPushButtonOverlayFill(true, option);
if (isDefaultButton)
return defaultButtonBackgroundColor;
return option.palette.brush(
isEnabled ? QPalette::Active : QPalette::Inactive, QPalette::Button);
}
std::optional<QBrush> getPushButtonFillOverlayBrush(const QStyleOptionButton &option)
{
const auto isDefaultButton = option.features.testFlag(QStyleOptionButton::DefaultButton);
const auto isOn = option.state.testFlag(QStyle::State_On);
if (isDefaultButton || isOn)
return std::nullopt;
const auto colorGroup = option.state.testFlag(QStyle::State_Enabled)
? QPalette::Active
: QPalette::Inactive;
if (option.palette.isBrushSet(colorGroup, QPalette::Button))
return std::nullopt;
if (const auto *themePalette =
QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::Palette::ButtonPalette)) {
const auto themeBrush = themePalette->brush(colorGroup, QPalette::Button);
if (option.palette.brush(colorGroup, QPalette::Button) != themeBrush)
return themeBrush;
}
return std::nullopt;
}
QColor getPushButtonTextColor(const QStyleOptionButton &option)
{
const auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
const auto isDefaultButton = option.features.testFlag(QStyleOptionButton::DefaultButton);
const auto isOn = option.state.testFlag(QStyle::State_On);
return isDefaultButton || isOn
? option.palette.color(QPalette::Active, QPalette::BrightText)
: option.palette.color(
isEnabled
? QPalette::Active
: QPalette::Disabled,
QPalette::ButtonText);
}
void drawPushButtonBackground(QPainter &painter, const QStyleOptionButton &option)
{
paintOnStackTop(painter, [&](QPainter &painter) {
const auto isMouseOver = option.state.testFlag(QStyle::State_MouseOver);
const auto isSunken = option.state.testFlag(QStyle::State_Sunken);
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(Qt::NoPen);
auto adjustment = pushButtonFocusFrameGap + pushButtonFocusFrameWidth;
auto rect = option.rect.adjusted(adjustment, adjustment, -adjustment, -adjustment);
painter.setBrush(getPushButtonBackgroundBrush(option));
painter.drawRoundedRect(rect, pushButtonCornerRadius, pushButtonCornerRadius);
const auto fillOverlayBrush = getPushButtonFillOverlayBrush(option);
if (fillOverlayBrush) {
painter.setBrush(*fillOverlayBrush);
painter.drawRoundedRect(rect, pushButtonCornerRadius, pushButtonCornerRadius);
}
if (isMouseOver || isSunken) {
painter.setBrush(getPushButtonOverlayFill(isSunken, option));
painter.drawRoundedRect(rect, pushButtonCornerRadius, pushButtonCornerRadius);
}
});
}
void drawPushButtonFocus(QPainter &painter, const QStyleOption &option)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.setBrush(Qt::NoBrush);
painter.setPen(QPen(option.palette.color(QPalette::Active, QPalette::Highlight), pushButtonFocusFrameWidth));
auto cornerRadius = pushButtonCornerRadius + pushButtonFocusFrameGap;
painter.drawRoundedRect(option.rect, cornerRadius, cornerRadius);
});
}
QRect getProgressBarGrooveRect(const QStyleOptionProgressBar &option)
{
auto rect = option.rect;
const bool horizontal = option.state & QStyle::State_Horizontal;
if (horizontal) {
rect.setHeight(progressBarGrooveHeight);
rect.moveTop(option.rect.center().y());
} else {
rect.setWidth(progressBarGrooveHeight);
rect.moveRight(option.rect.center().x());
}
return rect;
}
void drawProgressBarContent(QPainter &painter, const QStyleOptionProgressBar &option)
{
auto rect = getProgressBarGrooveRect(option);
const bool horizontal = option.state & QStyle::State_Horizontal;
const bool isIndeterminate = option.maximum == 0 && option.minimum == 0;
if (isIndeterminate) {
// TODO: proper busy indicator pending UI spec. Fill groove as a placeholder.
drawRoundedRect(painter, Qt::NoPen, option.palette.brush(QPalette::Highlight),
rect, progressBarCornerRadius, progressBarCornerRadius);
return;
}
const qint64 totalSteps = std::max(qint64(1), qint64(option.maximum) - option.minimum);
const double fraction = static_cast<double>(qint64(option.progress) - option.minimum)
/ static_cast<double>(totalSteps);
if (horizontal) {
rect.setWidth(fraction * rect.width());
rect.moveLeft(option.invertedAppearance ? option.rect.width() - rect.width() : 0);
} else {
rect.setHeight(fraction * rect.height());
rect.moveTop(option.invertedAppearance ? 0 : option.rect.height() - rect.height());
}
drawRoundedRect(
painter, Qt::NoPen, option.palette.brush(QPalette::Highlight), rect, progressBarCornerRadius,
progressBarCornerRadius);
}
void drawSliderGroove(QPainter &painter, const QStyleOptionSlider &option)
{
drawRoundedRect(
painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::Mid),
option.rect, sliderCornerRadius, sliderCornerRadius);
QRect fillRect;
if (option.orientation == Qt::Horizontal) {
const auto sliderPosition = QStyle::sliderPositionFromValue(
option.minimum, option.maximum, option.sliderPosition, option.rect.width(), option.upsideDown);
fillRect = QRect(option.rect.topLeft(), QSize(sliderPosition, option.rect.height()));
} else {
const auto sliderPosition = QStyle::sliderPositionFromValue(
option.minimum, option.maximum, option.sliderPosition, option.rect.height(), option.upsideDown);
fillRect = QRect(
option.rect.x(), option.rect.y() + sliderPosition, option.rect.width(), option.rect.height() - sliderPosition);
}
drawRoundedRect(
painter, Qt::NoPen, option.palette.brush(QPalette::Highlight), fillRect, sliderCornerRadius,
sliderCornerRadius);
}
void drawSliderThumb(QPainter &painter, const QStyleOptionSlider &option)
{
QRect shadowRect(0, 0, shadowXSRadius, shadowXSRadius);
shadowRect.moveCenter(option.rect.center());
QRadialGradient radialGrad(shadowRect.center(), shadowXSRadius * 1.0);
radialGrad.setColorAt(0.0, Qt::transparent);
radialGrad.setColorAt(1.0, option.palette.color(QPalette::Active, QPalette::Shadow));
drawEllipse(painter, Qt::NoPen, QBrush(radialGrad), shadowRect);
if (option.state.testFlag(QStyle::State_MouseOver))
drawEllipse(painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::Light), option.rect);
auto adjustedRect = option.rect.adjusted(sliderHoverSize, sliderHoverSize, -sliderHoverSize, -sliderHoverSize);
drawEllipse(painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::AlternateBase), adjustedRect);
if (option.state.testFlag(QStyle::State_Sunken))
drawEllipse(painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::Dark), adjustedRect);
if (option.state.testFlag(QStyle::State_HasFocus)) {
drawEllipse(
painter, QPen(option.palette.color(QPalette::Active, QPalette::Highlight), sliderFocusStrokeWidth),
Qt::NoBrush, adjusted(option.rect, -1));
}
}
void drawToolButton(QPainter &painter, const QStyleOption &option)
{
const auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
const auto isMouseOver = option.state.testFlag(QStyle::State_MouseOver);
const auto isSunken = option.state.testFlag(QStyle::State_Sunken);
drawRoundedRect(
painter, Qt::NoPen, option.palette.brush(isEnabled ? QPalette::Active : QPalette::Disabled, QPalette::Button),
option.rect, toolButtonCornerRadius, toolButtonCornerRadius);
if (isMouseOver || isSunken) {
drawRoundedRect(
painter, Qt::NoPen, getSunkenOrHoverColor(isSunken, option.palette), option.rect, toolButtonCornerRadius,
toolButtonCornerRadius);
}
}
void drawToolBarbackground(QPainter &painter, const QStyleOption &option)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.fillRect(option.rect, option.palette.brush(QPalette::Active, QPalette::Window));
});
}
void drawMenuBarBarbackground(QPainter &painter, const QStyleOption &option)
{
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setRenderHints(QPainter::Antialiasing);
painter.fillRect(option.rect, option.palette.brush(QPalette::Active, QPalette::Window));
});
}
void drawListItemSeparator(QPainter &painter, const QStyleOption &option)
{
QPoint center = option.rect.center();
drawLine(
painter, option.palette.color(QPalette::Active, QPalette::Mid),
QPoint(option.rect.left(), center.y()), QPoint(option.rect.right(), center.y()));
}
void drawMenuItem(QPainter &painter, const QStyleOptionMenuItem &option, int checkMarkSize, int iconSize)
{
const auto contentRect = option.rect.adjusted(itemViewItemHorizontalMargin, 0, -itemViewItemHorizontalMargin, 0);
if (option.menuItemType == QStyleOptionMenuItem::Separator) {
auto copyOption = option;
copyOption.rect = contentRect;
drawListItemSeparator(painter, copyOption);
} else {
const bool isSelected = option.state.testFlag(QStyle::State_Selected);
const bool isSunken = option.state.testFlag(QStyle::State_Sunken);
if (isSelected || isSunken) {
drawRoundedRect(
painter, Qt::NoPen, getSunkenOrHoverColor(isSunken, option.palette),
option.rect.adjusted(menuItemHoverHorizontalMargin, 0, -menuItemHoverHorizontalMargin, 0),
menuItemCornerRadius, menuItemCornerRadius);
}
const bool isCheckable = option.checkType != QStyleOptionMenuItem::NotCheckable;
QRect checkMarkRect;
if (isCheckable) {
checkMarkRect = contentRect;
checkMarkRect.setWidth(checkMarkSize);
auto copyOption = option;
copyOption.rect = checkMarkRect;
if (option.checked)
copyOption.state |= QStyle::State_On;
drawCheckBoxOrRadioButtonIndicator(painter, copyOption, true);
}
const bool hasIcon = !option.icon.isNull();
QRect iconRect;
if (hasIcon) {
iconRect = QRect(contentRect.x(), contentRect.center().y() - iconSize * 0.5, iconSize, iconSize);
iconRect.moveLeft(checkMarkRect.right() + itemViewItemHorizontalMargin);
option.icon.paint(
&painter, iconRect, Qt::AlignCenter,
option.state.testFlag(QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
option.checked ? QIcon::On : QIcon::Off);
}
QRect textRect = contentRect;
if (isCheckable)
textRect.setLeft(checkMarkRect.right() + itemViewItemHorizontalMargin);
if (hasIcon)
textRect.setLeft(iconRect.right() + itemViewItemHorizontalMargin);
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setPen(option.palette.color(QPalette::Text));
painter.drawText(
textRect, (Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic), option.text);
});
}
}
void drawMenuTearOff(QPainter &painter, const QStyleOption &option)
{
const auto pointY = option.rect.y() + option.rect.height() / 2;
drawLine(
painter, QPen(option.palette.color(QPalette::Text), 1, Qt::DashLine), QPoint(option.rect.x(), pointY),
QPoint(option.rect.x() + option.rect.width(), pointY)
);
}
void drawSplitter(QPainter &painter, const QStyleOption &option)
{
constexpr int splitterAvailableSizeDivider = 12;
const bool isHorizontal = option.state.testFlag(QStyle::State_Horizontal);
if (option.rect.width() > 1 && option.rect.height() > 1) {
const auto handleSize = isHorizontal
? QSize(splitterHandleWidth, option.rect.height() / splitterAvailableSizeDivider)
: QSize(option.rect.width() / splitterAvailableSizeDivider, splitterHandleWidth);
const auto handleRect = QRect(
QPoint(
(option.rect.width() - handleSize.width()) * 0.5,
(option.rect.height() - handleSize.height()) * 0.5),
handleSize);
const auto cornerRadius = std::min(handleSize.width(), handleSize.height()) * 0.5;
drawRoundedRect(
painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::Mid),
handleRect, cornerRadius, cornerRadius);
} else {
auto endPoint = isHorizontal ? option.rect.bottomLeft() : option.rect.topRight();
drawLine(painter, option.palette.dark().color(), option.rect.topLeft(), endPoint);
}
}
void drawSpinBoxFrame(
QPainter &painter, const QStyleOptionSpinBox &option, const QRect &frameRect, int frameWidth)
{
auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
QPen pen =
option.frame && option.subControls.testFlag(QStyle::SC_SpinBoxFrame)
? QPen(option.palette.color(QPalette::Active, QPalette::Mid), frameWidth)
: Qt::NoPen;
const qreal strokeInset = frameWidth / 2.0;
const QRectF strokeRect = QRectF(frameRect)
.adjusted(strokeInset, strokeInset, -strokeInset, -strokeInset);
paintOnStackTop(painter, [&](auto &p) {
p.setOpacity(isEnabled ? 1.0 : ohos_id_alpha_disabled);
drawRoundedRect(
p, pen, option.palette.window(), strokeRect, spinBoxFrameRadius, spinBoxFrameRadius);
});
}
void drawSpinBoxButton(QPainter &painter, const QStyleOptionSpinBox &option, int penWidth)
{
const bool isDownButton = option.subControls == QStyle::SC_SpinBoxDown;
const bool mirrored = option.direction == Qt::RightToLeft;
const qreal strokeInset = penWidth / 2.0;
const qreal outerLeftInset = mirrored ? strokeInset : 0.0;
const qreal outerRightInset = mirrored ? 0.0 : -strokeInset;
const QRectF rect = isDownButton
? QRectF(option.rect).adjusted(outerLeftInset, 0.0, outerRightInset, -strokeInset)
: QRectF(option.rect).adjusted(outerLeftInset, strokeInset, outerRightInset, 0.0);
auto isEnabled = option.state.testFlag(QStyle::State_Enabled);
auto isPressed = option.state.testFlag(QStyle::State_Sunken);
QPen pen(option.palette.color(QPalette::Active, QPalette::Mid), penWidth);
QBrush brush(option.palette.window());
if (isPressed)
brush = QBrush(option.palette.highlight());
const qreal topLeftRadius = (mirrored && !isDownButton) ? spinBoxFrameRadius : 0.0;
const qreal topRightRadius = (!mirrored && !isDownButton) ? spinBoxFrameRadius : 0.0;
const qreal bottomLeftRadius = (mirrored && isDownButton) ? spinBoxFrameRadius : 0.0;
const qreal bottomRightRadius = (!mirrored && isDownButton) ? spinBoxFrameRadius : 0.0;
paintOnStackTop(painter, [&](auto &p) {
p.setOpacity(isEnabled ? 1.0 : ohos_id_alpha_disabled);
drawRoundedRect(
p, pen, brush, rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
});
}
void drawScrollBarSlider(QPainter &painter, const QStyleOptionSlider &option)
{
int scrollBarRadius =
option.orientation == Qt::Vertical
? option.rect.width() * 0.5
: option.rect.height() * 0.5;
paintOnStackTop(painter, [&](QPainter &painter) {
painter.setOpacity(ohos_id_alpha_content_tertiary);
drawRoundedRect(
painter, Qt::NoPen, option.palette.color(QPalette::Active, QPalette::Midlight),
option.rect, scrollBarRadius, scrollBarRadius);
});
}
Qt::Orientation tabBarShapeToOrientation(QTabBar::Shape shape)
{
switch (shape) {
case QTabBar::RoundedNorth:
case QTabBar::RoundedSouth:
case QTabBar::TriangularNorth:
case QTabBar::TriangularSouth:
return Qt::Horizontal;
case QTabBar::RoundedWest:
case QTabBar::TriangularWest:
case QTabBar::RoundedEast:
case QTabBar::TriangularEast:
return Qt::Vertical;
}
}
void drawTabBarTabShape(QPainter &painter, const QStyleOptionTab &option)
{
auto isSelected = option.state.testFlag(QStyle::State_Selected);
auto isFocused = option.state.testFlag(QStyle::State_HasFocus);
QRect rect(option.rect);
adjusted(rect, -tabBarTabFrameWidth - 1);
QPoint underLineStart, underLineEnd;
if (tabBarShapeToOrientation(option.shape) == Qt::Horizontal) {
int lineY = rect.y() + rect.height() - tabBarTabUnderLineWidth;
underLineStart = QPoint(rect.x() + tabBarTabRadius, lineY);
underLineEnd = QPoint(rect.x() + rect.width() - tabBarTabRadius, lineY);
} else {
int lineX = rect.x();
if (option.shape == QTabBar::RoundedWest || option.shape == QTabBar::TriangularWest)
lineX += rect.width() - tabBarTabUnderLineWidth;
else
lineX += tabBarTabUnderLineWidth;
underLineStart = QPoint(lineX, rect.y() + tabBarTabRadius);
underLineEnd = QPoint(lineX, rect.y() + rect.height() - tabBarTabRadius);
}
drawRoundedRect(painter, Qt::NoPen, option.palette.window(), rect, tabBarTabRadius, tabBarTabRadius);
if (!isFocused && isSelected)
drawLine(painter, QPen(option.palette.highlight(), tabBarTabUnderLineWidth), underLineStart, underLineEnd);
}
void drawComboBoxFrame(QPainter &painter, const QStyleOptionComboBox &option)
{
const auto isMouseOver = option.state.testFlag(QStyle::State_MouseOver);
const auto isOpened = option.state.testFlag(QStyle::State_On);
const auto isFocused = option.state.testFlag(QStyle::State_HasFocus);
auto focusedPen = QPen(
option.palette.color(QPalette::Active, QPalette::AlternateBase),
comboBoxFocusFrameWidth);
const auto buttonBrush = option.palette.brush(QPalette::Button);
drawRoundedRect(
painter, isFocused ? focusedPen : Qt::NoPen, buttonBrush, option.rect,
comboBoxFrameRadius, comboBoxFrameRadius);
const auto *ohosThemePalette =
QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::Palette::ComboBoxPalette);
const auto overlayButtonBrush = ohosThemePalette->brush(QPalette::Button);
bool shouldPresentOverlayForOverriddenButtonBrush = buttonBrush != overlayButtonBrush;
if (shouldPresentOverlayForOverriddenButtonBrush)
drawRoundedRect(
painter, Qt::NoPen, overlayButtonBrush, option.rect, comboBoxFrameRadius, comboBoxFrameRadius);
if (isMouseOver || isOpened) {
auto pen = isOpened ? focusedPen : Qt::NoPen;
auto brush = getSunkenOrHoverColor(isOpened, option.palette);
drawRoundedRect(painter, pen, brush, option.rect, comboBoxFrameRadius, comboBoxFrameRadius);
}
}
void drawComboBoxListViewItem(QPainter &painter, const QStyleOptionViewItem &option, const QBrush &brush)
{
if (isFirstItem(option.index)) {
drawRoundedRect(
painter, Qt::NoPen, brush, option.rect, focusFrameCornerRadius, focusFrameCornerRadius, 0, 0);
} else if (isLastItem(option.index)) {
drawRoundedRect(
painter, Qt::NoPen, brush, option.rect, 0, 0, focusFrameCornerRadius, focusFrameCornerRadius);
} else {
drawRect(painter, Qt::NoPen, brush, option.rect);
}
}
void drawTreeViewHighlightItem(QPainter &painter, const QStyleOptionViewItem &option, const QBrush &brush)
{
switch (option.viewItemPosition) {
case QStyleOptionViewItem::OnlyOne:
drawRoundedRect(
painter, Qt::NoPen, brush, option.rect, focusFrameCornerRadius, focusFrameCornerRadius);
break;
case QStyleOptionViewItem::Beginning:
drawRoundedRect(
painter, Qt::NoPen, brush, option.rect, focusFrameCornerRadius, 0, focusFrameCornerRadius, 0);
break;
case QStyleOptionViewItem::Invalid:
case QStyleOptionViewItem::Middle:
drawRect(painter, Qt::NoPen, brush, option.rect);
break;
case QStyleOptionViewItem::End:
drawRoundedRect(
painter, Qt::NoPen, brush, option.rect, 0, focusFrameCornerRadius, 0, focusFrameCornerRadius);
break;
}
}
void drawPanelItemViewItem(QPainter &painter, const QStyleOptionViewItem &option, bool isComboBoxListViewItem)
{
if (isItemViewSeparator(option.index)) {
auto copyOption = option;
copyOption.rect = option.rect.adjusted(itemViewItemHorizontalMargin, 0, -itemViewItemHorizontalMargin, 0);
drawListItemSeparator(painter, copyOption);
} else {
auto isSelected = option.state.testFlag(QStyle::State_Selected);
auto isMouseOver = option.state.testFlag(QStyle::State_MouseOver);
auto colorGroup = option.state.testFlag(QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled;
if (colorGroup == QPalette::Normal && !option.state.testFlag(QStyle::State_Active))
colorGroup = QPalette::Inactive;
const QBrush brush =
isSelected
? option.palette.brush(colorGroup, QPalette::Highlight)
: isMouseOver
? option.palette.color(QPalette::Active, QPalette::Light)
: option.backgroundBrush.style() == Qt::NoBrush
? Qt::NoBrush
: option.backgroundBrush;
if (isComboBoxListViewItem)
drawComboBoxListViewItem(painter, option, brush);
else
drawTreeViewHighlightItem(painter, option, brush);
}
}
void drawHeaderSection(QPainter &painter, const QStyleOptionHeader &option)
{
QRect rect =
option.position == QStyleOptionHeader::OnlyOneSection
? option.rect
: option.orientation == Qt::Horizontal
? option.rect.adjusted(-1, 0, 0, 0)
: option.rect.adjusted(0, -1, 0, 0);
drawRect(painter, QPen(Qt::black), option.palette.brush(QPalette::Button), rect);
}
void drawWindowBackgroundAndFrame(
QPainter &painter, const QStyleOptionFrame &option, QFlags<Qt::WindowState> state, int titleBarHeight)
{
const auto offset = option.lineWidth * 0.5;
const auto windowFrameColor =
state.testFlag(Qt::WindowActive)
? option.palette.color(QPalette::Active, QPalette::Base)
: option.palette.color(QPalette::Inactive, QPalette::Base);
if (state.testFlag(Qt::WindowMinimized)) {
drawRoundedRect(
painter, QPen(windowFrameColor, option.lineWidth), Qt::NoBrush,
option.rect.adjusted(offset, offset, -offset, -offset), focusFrameCornerRadius, focusFrameCornerRadius, 0,
0);
drawRect(
painter, Qt::NoPen, option.palette.brush(QPalette::Window),
option.rect.adjusted(option.lineWidth, titleBarHeight, -option.lineWidth, 0));
} else {
drawRoundedRect(
painter, Qt::NoPen, windowFrameColor, option.rect.adjusted(0, titleBarHeight, 0, 0), 0, 0,
focusFrameCornerRadius, focusFrameCornerRadius);
drawRoundedRect(
painter, Qt::NoPen, option.palette.brush(QPalette::Window),
option.rect.adjusted(option.lineWidth, titleBarHeight, -option.lineWidth, -option.lineWidth),
focusFrameCornerRadius, focusFrameCornerRadius);
drawRoundedRect(
painter, QPen(windowFrameColor, option.lineWidth), Qt::NoBrush,
option.rect.adjusted(offset, offset, -offset, -offset), focusFrameCornerRadius, focusFrameCornerRadius);
}
}
void drawToolTip(QPainter &painter, const QStyleOptionFrame &option)
{
drawRoundedRect(
painter, option.palette.color(QPalette::Active, QPalette::Base),
option.palette.toolTipBase(), option.rect, toolTipCornerRadius,
toolTipCornerRadius);
}
QRect titleBarSubControlRect(const QStyleOptionTitleBar &option, QCommonStyle::SubControl subControl)
{
const bool isMinimized = (option.titleBarState & Qt::WindowMinimized) != 0;
const bool isMaximized = (option.titleBarState & Qt::WindowMaximized) != 0;
const bool hasTitle = option.titleBarFlags.testFlag(Qt::WindowTitleHint);
const bool hasSystemMenuButton = option.titleBarFlags.testFlag(Qt::WindowSystemMenuHint);
const bool hasShadeButton = option.titleBarFlags.testFlag(Qt::WindowShadeButtonHint);
const bool hasContextHelpButton = option.titleBarFlags.testFlag(Qt::WindowContextHelpButtonHint);
const bool hasMinimizeButton = option.titleBarFlags.testFlag(Qt::WindowMinimizeButtonHint);
const bool hasMaximizeButton = option.titleBarFlags.testFlag(Qt::WindowMaximizeButtonHint);
const auto controlSize = QSize(30, 30);
const int titleBarHorizontalMargin = 25;
const int titleBarControlVerticalMargin = 15;
const auto titleBarContentRect = QRect(
option.rect.x() + titleBarHorizontalMargin, (option.rect.height() - controlSize.height()) / 2,
option.rect.width() - 2 * titleBarHorizontalMargin, controlSize.height());
const auto titleBarContentRectRight = titleBarContentRect.x() + titleBarContentRect.width();
const auto delta = controlSize.width() + titleBarControlVerticalMargin;
QRect result;
switch (subControl) {
case QCommonStyle::SC_TitleBarSysMenu:
if (hasSystemMenuButton)
result = QRect(titleBarContentRect.topLeft(), controlSize);
break;
case QCommonStyle::SC_TitleBarLabel:
if (hasTitle) {
result = titleBarContentRect;
if (hasSystemMenuButton)
result.adjust(delta, 0, -delta, 0);
if (hasMinimizeButton)
result.adjust(0, 0, -delta, 0);
if (hasMaximizeButton)
result.adjust(0, 0, -delta, 0);
if (hasShadeButton)
result.adjust(0, 0, -delta, 0);
if (hasContextHelpButton)
result.adjust(0, 0, -delta, 0);
}
break;
case QCommonStyle::SC_TitleBarMaxButton:
if (!isMaximized && hasMaximizeButton) {
result = QRect(
QPoint(titleBarContentRectRight - 3 * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
}
break;
case QCommonStyle::SC_TitleBarNormalButton:
if (isMinimized && hasMinimizeButton) {
result = QRect(
QPoint(titleBarContentRectRight - 2 * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
} else if (isMaximized && hasMaximizeButton) {
result = QRect(
QPoint(titleBarContentRectRight - 3 * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
}
break;
case QCommonStyle::SC_TitleBarMinButton:
if (!isMinimized && hasMinimizeButton) {
result = QRect(
QPoint(titleBarContentRectRight - 2 * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
}
break;
case QCommonStyle::SC_TitleBarCloseButton:
result = QRect(
QPoint(titleBarContentRectRight - controlSize.width(), titleBarContentRect.y()), controlSize);
break;
case QCommonStyle::SC_TitleBarShadeButton:
case QCommonStyle::SC_TitleBarUnshadeButton:
result = QRect(
QPoint(titleBarContentRectRight - 4 * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
break;
case QCommonStyle::SC_TitleBarContextHelpButton:
result = QRect(
QPoint(titleBarContentRectRight - (hasShadeButton ? 5 : 4) * delta + titleBarControlVerticalMargin,
titleBarContentRect.y()), controlSize);
break;
default:
break;
}
return result;
}
}
QOhosStyle::QOhosStyle()
: QCommonStyle()
{
}
void QOhosStyle::drawPrimitive(
PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
switch (element) {
case PE_Frame: {
if (qobjectIsInstanceOf<QAbstractScrollArea>(widget)) {
if (const auto *frameOption = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
const int frameWidth = frameOption->lineWidth;
drawRect(
*painter, QPen(option->palette.color(QPalette::Active, QPalette::Mid), frameWidth), Qt::NoBrush,
adjusted(frameOption->rect, -frameWidth));
} else {
QCommonStyle::drawPrimitive(element, option, painter, widget);
}
} else if (widget && !qobjectIsInstanceOf<QComboBox>(widget->parent())) {
QCommonStyle::drawPrimitive(element, option, painter, widget);
}
break;
}
case PE_FrameWindow:
if (qStyleOptionIs<QStyleOptionFrame>(option)) {
drawWindowBackgroundAndFrame(
*painter, *qstyleoption_cast<const QStyleOptionFrame *>(option), widget->windowState(),
pixelMetric(PM_TitleBarHeight, option, widget));
}
break;
case PE_FrameFocusRect:
if (qstyleoption_cast<const QStyleOptionFocusRect *>(option)) {
if (qobjectIsInstanceOf<QPushButton>(widget)) {
drawPushButtonFocus(*painter, *option);
} else if (qobjectIsInstanceOf<QToolButton>(widget)) {
const auto menuButtonIndicatorSize =
qobject_cast<const QToolButton *>(widget)->popupMode() == QToolButton::MenuButtonPopup
? pixelMetric(PM_MenuButtonIndicator, option, widget)
: 0;
drawRoundedRect(
*painter,
QPen(option->palette.color(QPalette::Active, QPalette::Highlight), toolButtonFocusFrameWidth),
Qt::NoBrush, option->rect.adjusted(-1, -1, 1 + menuButtonIndicatorSize, 1),
toolButtonCornerRadius, toolButtonCornerRadius);
} else if (qobjectIsInstanceOf<QCheckBox>(widget) || qobjectIsInstanceOf<QRadioButton>(widget)) {
drawEllipse(
*painter, QPen(option->palette.color(QPalette::Active, QPalette::Highlight),
checkBoxOrRadioButtonFocusStrokeWidth), Qt::NoBrush, option->rect);
} else if (qobjectIsInstanceOf<QTabBar>(widget)) {
drawRoundedRect(
*painter, QPen(option->palette.highlight(), tabBarTabFrameWidth), Qt::NoBrush,
option->rect, tabBarTabRadius, tabBarTabRadius);
} else {
drawRoundedRect(
*painter, QPen(option->palette.color(QPalette::Active, QPalette::Highlight), focusFrameWidth),
Qt::NoBrush, option->rect, focusFrameCornerRadius, focusFrameCornerRadius);
}
}
break;
case PE_PanelButtonCommand:
if (qStyleOptionIs<QStyleOptionButton>(option))
drawPushButtonBackground(*painter, *qstyleoption_cast<const QStyleOptionButton *>(option));
break;
case PE_PanelButtonTool:
if (qobjectIsInstanceOf<QMdiSubWindow>(widget)) {
const QPalette *toolButtonThemePalette =
QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::Palette::ToolButtonPalette);
const auto panelButtonColor =
toolButtonThemePalette->color(QPalette::Active, QPalette::AlternateBase);
drawEllipse(
*painter, Qt::NoPen,
widget->windowState().testFlag(Qt::WindowActive)
? panelButtonColor
: makeInactiveOrDisabledFromColor(panelButtonColor),
option->rect);
} else {
const QToolButton *toolButton = qobject_cast<const QToolButton *>(widget);
const auto menuButtonIndicatorSize =
toolButton != nullptr && toolButton->popupMode() == QToolButton::MenuButtonPopup
? pixelMetric(PM_MenuButtonIndicator, option, widget)
: 0;
auto optionCopy = *option;
optionCopy.rect.setWidth(option->rect.width() + menuButtonIndicatorSize);
drawToolButton(*painter, optionCopy);
}
break;
case PE_PanelMenuBar:
drawMenuBarBarbackground(*painter, *option);
break;
case PE_IndicatorCheckBox:
drawCheckBoxOrRadioButtonIndicator(*painter, *option, true);
break;
case PE_IndicatorRadioButton:
drawCheckBoxOrRadioButtonIndicator(*painter, *option, false);
break;
case PE_PanelLineEdit: {
// HACK: Q(Abstrace)SpinBox contains a QLineEdit inside, which is painted separately from
// the QSpinBox itself. We will be drawing the whole QSpinBox in the drawComplexControl.
if (widget != nullptr && qobjectIsInstanceOf<QAbstractSpinBox>(widget->parentWidget()))
break;
// HACK: QComboBox in editable mode presents line edit in the center. This line edit is drawn
// above QComboBox. There are two issues here: QComboBox has different base color than line edit.
// Second, line edit and QComboBox has the same size - so drawing a line edit overlays a frame border.
// To fix above, do not draw line edit background.
if (widget != nullptr && qobjectIsInstanceOf<QComboBox>(widget->parentWidget()))
break;
// HACK: while editing Tree View/Widget item - line edit component is presented above it. If the line edit has
// some opacity in background content below it (item content) is visible. This causes an effect that original
// text is still visible while editing. To fix it, override background (base) color and use solid color value.
auto optionCopy = *option;
if (widget != nullptr && qstrcmp(widget->metaObject()->className(), "QExpandingLineEdit") == 0) {
optionCopy.palette.setColor(
QPalette::Base,
option->palette.color(QPalette::Active, QPalette::AlternateBase));
}
drawLineEditBackground(*painter, optionCopy);
break;
}
case PE_PanelButtonBevel:
if (qStyleOptionIs<QStyleOptionSpinBox>(option)) {
drawSpinBoxButton(
*painter, *qstyleoption_cast<const QStyleOptionSpinBox *>(option),
pixelMetric(PM_SpinBoxFrameWidth, option, widget));
}
break;
case PE_IndicatorSpinDown:
case PE_IndicatorSpinUp: {
// HACK: QCommonStyle adjusts the indicator left as follows: copy.rect.adjust(3, 0, -4, 0);
// However, Ohos requires 4 pixels of horizontal margin and 2 pixels of vertical margin
QRect indicatorRect = option->rect.adjusted(1, 2, 0, -2);
constexpr int arrowWidth = 2;
auto x = indicatorRect.x();
auto y = indicatorRect.y();
auto width = indicatorRect.width();
auto height = indicatorRect.height();
auto verticalSpacing = 4;
auto horizontalSpacing = 7;
qreal x1 = x + horizontalSpacing;
qreal x2 = x + width * 0.5;
qreal x3 = x + width - horizontalSpacing;
qreal y1, y2;
if (element == PE_IndicatorSpinDown) {
y1 = y + verticalSpacing;
y2 = y + height - verticalSpacing;
} else {
y1 = y + height - verticalSpacing;
y2 = y + verticalSpacing;
}
auto y3 = y1;
QPen indicatorPen(option->palette.color(QPalette::Active, QPalette::Text), arrowWidth);
indicatorPen.setCapStyle(Qt::RoundCap);
indicatorPen.setJoinStyle(Qt::RoundJoin);
paintOnStackTop(*painter, [&](auto &p) {
p.setOpacity(option->state.testFlag(State_Enabled) ? 1.0 : ohos_id_alpha_disabled);
p.setRenderHint(QPainter::Antialiasing);
p.setPen(indicatorPen);
p.setBrush(Qt::NoBrush);
p.drawLine(x1, y1, x2, y2);
p.drawLine(x2, y2, x3, y3);
});
break;
}
case PE_FrameGroupBox: {
const auto frame = qstyleoption_cast<const QStyleOptionFrame *>(option);
if (frame != nullptr) {
QPen pen;
pen.setColor(option->palette.mid().color());
pen.setStyle(
frame->features.testFlag(QStyleOptionFrame::FrameFeature::Flat)
? Qt::NoPen : Qt::SolidLine);
painter->setClipRegion(frame->rect);
drawRoundedRect(
*painter, pen, option->palette.window(), frame->rect, groupBoxFrameCornerRadius,
groupBoxFrameCornerRadius);
}
break;
}
case PE_IndicatorArrowUp:
case PE_IndicatorArrowDown:
case PE_IndicatorArrowLeft:
case PE_IndicatorArrowRight: {
QRect availableRect;
int maxArrowSize = 0;
if (qobjectIsInstanceOf<QComboBox>(widget)) {
availableRect = option->rect;
maxArrowSize = std::min(availableRect.width(), availableRect.height()) * 0.5;
} else if (qobjectIsInstanceOf<QToolButton>(widget) || qobjectIsInstanceOf<QPushButton>(widget)) {
const auto menuButtonIndicatorSize = pixelMetric(PM_MenuButtonIndicator, option, widget);
availableRect = QRect(
widget->size().width() - menuButtonIndicatorSize, 0, menuButtonIndicatorSize, widget->size().height());
maxArrowSize = std::min(availableRect.width(), availableRect.height()) * 0.5;
} else {
availableRect = option->rect;
maxArrowSize = std::min(availableRect.width(), availableRect.height());
}
auto direction = ArrowDirection::Down;
switch (element) {
default:
case PE_IndicatorArrowDown:
break;
case PE_IndicatorArrowUp:
direction = ArrowDirection::Up;
break;
case PE_IndicatorArrowLeft:
direction = ArrowDirection::Left;
break;
case PE_IndicatorArrowRight:
direction = ArrowDirection::Right;
break;
}
const auto isEnabled = option->state.testFlag(QStyle::State_Enabled);
paintOnStackTop(*painter, [&](auto &p) {
p.setOpacity(isEnabled ? 1.0 : ohos_id_alpha_disabled);
drawArrow(
p, availableRect, maxArrowSize, direction,
option->palette.color(QPalette::Active, QPalette::WindowText));
});
break;
}
case PE_IndicatorButtonDropDown: {
if (qobjectIsInstanceOf<QToolButton>(widget))
break;
QCommonStyle::drawPrimitive(element, option, painter, widget);
break;
}
case PE_IndicatorHeaderArrow: {
const auto headerOption = qstyleoption_cast<const QStyleOptionHeader *>(option);
if (headerOption == nullptr || headerOption->sortIndicator == QStyleOptionHeader::None)
break;
const auto direction = headerOption->sortIndicator == QStyleOptionHeader::SortDown
? ArrowDirection::Up
: ArrowDirection::Down;
drawArrow(
*painter, option->rect, option->rect.width(), direction,
option->palette.color(QPalette::Active, QPalette::ButtonText));
break;
}
case PE_PanelItemViewItem:
if (qStyleOptionIs<QStyleOptionViewItem>(option)) {
drawPanelItemViewItem(
*painter, *qstyleoption_cast<const QStyleOptionViewItem *>(option),
widget != nullptr && qstrcmp(widget->metaObject()->className(), "QComboBoxListView") == 0);
}
break;
case PE_FrameTabWidget:
if (qStyleOptionIs<QStyleOptionTabWidgetFrame>(option)) {
QRect rect = option->rect;
switch (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)->shape) {
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
rect.adjust(0, tabWidgetFrameWidth, 0, 0);
break;
case QTabBar::RoundedWest:
case QTabBar::TriangularWest:
rect.adjust(tabWidgetFrameWidth, 0, 0, 0);
break;
case QTabBar::RoundedSouth:
case QTabBar::TriangularSouth:
rect.adjust(0, 0, 0, -(tabWidgetFrameWidth * 2));
break;
case QTabBar::RoundedEast:
case QTabBar::TriangularEast:
rect.adjust(0, 0, -(tabWidgetFrameWidth * 2), 0);
break;
}
drawRect(
*painter, QPen(option->palette.color(QPalette::Dark), tabWidgetFrameWidth),
Qt::NoBrush, rect);
}
break;
case PE_PanelTipLabel:
if (qStyleOptionIs<QStyleOptionFrame>(option))
drawToolTip(*painter, *qstyleoption_cast<const QStyleOptionFrame *>(option));
break;
default:
QCommonStyle::drawPrimitive(element, option, painter, widget);
break;
}
}
void QOhosStyle::drawControl(
ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
switch (element) {
case CE_HeaderSection:
if (qStyleOptionIs<QStyleOptionHeader>(option))
drawHeaderSection(*painter, *qstyleoption_cast<const QStyleOptionHeader *>(option));
break;
case CE_MenuBarEmptyArea:
break;
case CE_MenuItem:
if (qStyleOptionIs<QStyleOptionMenuItem>(option)) {
const auto *menuItemStyleOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
drawMenuItem(
*painter, *menuItemStyleOption, pixelMetric(PM_IndicatorWidth, option, widget),
pixelMetric(PM_SmallIconSize, option, widget));
if (menuItemStyleOption->menuItemType == QStyleOptionMenuItem::SubMenu) {
const auto iconSize = pixelMetric(PM_SmallIconSize, option, widget);
const auto menuItemRect = menuItemStyleOption->rect;
QStyleOptionMenuItem menuArrowStyleOption = *menuItemStyleOption;
menuArrowStyleOption.rect = QRect(
menuItemRect.right() - itemViewItemHorizontalMargin - iconSize,
menuItemRect.top() + (menuItemRect.height() - iconSize) / 2, iconSize, iconSize);
QColor arrowColor = menuItemStyleOption->palette.color(QPalette::Active, QPalette::Text);
menuArrowStyleOption.palette.setColor(
QPalette::Active, QPalette::WindowText, arrowColor);
drawPrimitive(
menuArrowStyleOption.direction == Qt::RightToLeft ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight,
&menuArrowStyleOption, painter, widget);
}
}
break;
case CE_MenuTearoff:
drawMenuTearOff(*painter, *option);
break;
case CE_ProgressBarGroove:
if (qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
drawRoundedRect(
*painter, Qt::NoPen, option->palette.color(QPalette::Active, QPalette::Mid),
getProgressBarGrooveRect(*qstyleoption_cast<const QStyleOptionProgressBar *>(option)),
progressBarCornerRadius, progressBarCornerRadius);
}
break;
case CE_ProgressBarContents:
if (qstyleoption_cast<const QStyleOptionProgressBar *>(option))
drawProgressBarContent(*painter, *qstyleoption_cast<const QStyleOptionProgressBar *>(option));
break;
case CE_ProgressBarLabel:
break;
case CE_Splitter:
drawSplitter(*painter, *option);
break;
case CE_ToolBar:
drawToolBarbackground(*painter, *option);
break;
case CE_ScrollBarSlider:
if (qStyleOptionIs<QStyleOptionSlider>(option))
drawScrollBarSlider(*painter, *qstyleoption_cast<const QStyleOptionSlider *>(option));
break;
case CE_TabBarTabShape: {
auto tabOption = qstyleoption_cast<const QStyleOptionTab *>(option);
if (tabOption != nullptr)
drawTabBarTabShape(*painter, *tabOption);
break;
}
case CE_TabBarTabLabel: {
auto tabOption = qstyleoption_cast<const QStyleOptionTab *>(option);
if (tabOption != nullptr) {
auto copy = *tabOption;
if (!option->state.testFlag(State_Selected))
copy.palette.setCurrentColorGroup(QPalette::Inactive);
QCommonStyle::drawControl(element, &copy, painter, widget);
}
break;
}
case CE_PushButtonLabel: {
if (qStyleOptionIs<QStyleOptionButton>(option)) {
auto buttonOption = qstyleoption_cast<const QStyleOptionButton *>(option);
auto buttonOptionCopy = *buttonOption;
buttonOptionCopy.palette.setColor(QPalette::ButtonText, getPushButtonTextColor(*buttonOption));
QCommonStyle::drawControl(element, &buttonOptionCopy, painter, widget);
}
break;
}
case CE_DockWidgetTitle: {
const auto *dockWidgetOption = qstyleoption_cast<const QStyleOptionDockWidget *>(option);
if (dockWidgetOption == nullptr)
break;
auto dockWidgetOptionCopy = *dockWidgetOption;
if (!dockWidgetOptionCopy.title.isEmpty()) {
QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget);
if (dockWidgetOptionCopy.verticalTitleBar) {
QRect rect = dockWidgetOptionCopy.rect;
QRect verticalRect = rect.transposed();
titleRect = QRect(
verticalRect.left() + rect.bottom() - titleRect.bottom(),
verticalRect.top() + titleRect.left() - rect.left(),
titleRect.height(),
titleRect.width());
}
dockWidgetOptionCopy.title = painter->fontMetrics().elidedText(
dockWidgetOptionCopy.title, Qt::ElideRight, titleRect.width());
}
QCommonStyle::drawControl(element, &dockWidgetOptionCopy, painter, widget);
break;
}
default:
QCommonStyle::drawControl(element, option, painter, widget);
}
}
void QOhosStyle::drawComplexControl(
ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const
{
switch (control) {
case CC_Slider: {
const auto sliderStyleOption = qstyleoption_cast<const QStyleOptionSlider *>(option);
if (sliderStyleOption != nullptr) {
if (option->subControls.testFlag(SC_SliderGroove)) {
auto sliderStyleOptionCopy = *sliderStyleOption;
sliderStyleOptionCopy.rect = subControlRect(control, option, SC_SliderGroove, widget);
drawSliderGroove(*painter, sliderStyleOptionCopy);
}
if (option->subControls.testFlag(SC_SliderHandle)) {
auto sliderStyleOptionCopy = *sliderStyleOption;
sliderStyleOptionCopy.rect = subControlRect(control, option, SC_SliderHandle, widget);
drawSliderThumb(*painter, sliderStyleOptionCopy);
}
}
break;
}
case CC_SpinBox:
if (qStyleOptionIs<QStyleOptionSpinBox>(option)) {
auto spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option);
auto frameRect = subControlRect(control, spinBox, SC_SpinBoxFrame, widget);
auto frameWidth = pixelMetric(PM_SpinBoxFrameWidth, spinBox, widget);
drawSpinBoxFrame(*painter, *spinBox, frameRect, frameWidth);
auto copy = *spinBox;
copy.frame = false;
QCommonStyle::drawComplexControl(control, &copy, painter, widget);
}
break;
case CC_ScrollBar: {
const auto scrollBarStyleOption = qstyleoption_cast<const QStyleOptionSlider *>(option);
if (scrollBarStyleOption != nullptr) {
if (option->subControls.testFlag(SC_ScrollBarSlider)) {
auto scrollBarStyleOptionCopy = *scrollBarStyleOption;
scrollBarStyleOptionCopy.rect = subControlRect(control, option, SC_ScrollBarSlider, widget);
drawControl(CE_ScrollBarSlider, &scrollBarStyleOptionCopy, painter, widget);
}
}
break;
}
case CC_GroupBox: {
if (qStyleOptionIs<QStyleOptionGroupBox>(option)) {
auto groupBox = *qstyleoption_cast<const QStyleOptionGroupBox *>(option);
groupBox.textAlignment |= Qt::AlignVCenter;
const auto colorGroup = option->state.testFlag(QStyle::State_Enabled)
? QPalette::Active
: QPalette::Disabled;
if (!groupBox.palette.isBrushSet(colorGroup, QPalette::WindowText))
groupBox.textColor = groupBox.palette.color(QPalette::Text);
const auto titleFont = getGroupBoxTitleFont(widget);
painter->setFont(titleFont);
QCommonStyle::drawComplexControl(control, &groupBox, painter, widget);
}
break;
}
case CC_ComboBox: {
if (qStyleOptionIs<QStyleOptionComboBox>(option)) {
const auto comboBoxStyleOption = qstyleoption_cast<const QStyleOptionComboBox *>(option);
if (option->subControls.testFlag(SC_ComboBoxFrame)) {
auto comboBoxStyleOptionCopy = *comboBoxStyleOption;
comboBoxStyleOptionCopy.rect = subControlRect(control, option, SC_ComboBoxFrame, widget);
drawComboBoxFrame(*painter, comboBoxStyleOptionCopy);
}
if (option->subControls.testFlag(SC_ComboBoxArrow)) {
auto optionCopy = *option;
auto comboBoxOptions = static_cast<QStyleOption *>(&optionCopy);
comboBoxOptions->rect = subControlRect(control, option, SC_ComboBoxArrow, widget);
drawPrimitive(PE_IndicatorArrowDown, comboBoxOptions, painter, widget);
}
} else {
QCommonStyle::drawComplexControl(control, option, painter, widget);
}
break;
}
default:
QCommonStyle::drawComplexControl(control, option, painter, widget);
}
}
QRect QOhosStyle::subControlRect(
ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const
{
switch (control) {
case CC_Slider:
if (qStyleOptionIs<QStyleOptionSlider>(option)) {
const auto sliderStyleOption = qstyleoption_cast<const QStyleOptionSlider *>(option);
switch (subControl) {
case SC_SliderGroove: {
const auto sliderLengthOffset = pixelMetric(PM_SliderLength, option, widget) * 0.5;
auto grooveRect = QCommonStyle::subControlRect(control, option, subControl, widget);
if (sliderStyleOption->orientation == Qt::Horizontal) {
grooveRect.adjust(sliderLengthOffset, 0, -sliderLengthOffset, 0);
grooveRect.setHeight(sliderGrooveHeight);
grooveRect.moveTop(option->rect.center().y() - sliderGrooveHeight * 0.5);
} else {
grooveRect.adjust(0, sliderLengthOffset, 0, -sliderLengthOffset);
grooveRect.setWidth(sliderGrooveHeight);
grooveRect.moveLeft(option->rect.center().x() - sliderGrooveHeight * 0.5);
}
return grooveRect;
}
case SC_SliderHandle: {
auto handleRect = QCommonStyle::subControlRect(control, option, subControl, widget);
if (sliderStyleOption->orientation == Qt::Horizontal)
handleRect.moveTop(option->rect.center().y() - handleRect.height() * 0.5);
else
handleRect.moveLeft(option->rect.center().x() - handleRect.width() * 0.5);
return handleRect;
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
case CC_SpinBox:
if (qStyleOptionIs<QStyleOptionSpinBox>(option)) {
const auto spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option);
auto frameWidth = spinBox->frame ? pixelMetric(PM_SpinBoxFrameWidth, option, widget) : 0;
switch (subControl) {
case SC_SpinBoxFrame: {
auto frameRect = spinBox->rect;
frameRect.setHeight(spinBoxFrameHeight);
frameRect.moveCenter(spinBox->rect.center());
return visualRect(spinBox->direction, spinBox->rect, frameRect);
}
case SC_SpinBoxDown:
case SC_SpinBoxUp: {
auto frameRect = subControlRect(CC_SpinBox, option, SC_SpinBoxFrame, widget);
if (spinBox->buttonSymbols == QAbstractSpinBox::NoButtons)
return QRect();
auto buttonRect = QRect(
frameRect.left() + frameRect.width() - spinBoxButtonBoxWidth,
frameRect.top() + (frameRect.height() - spinBoxFrameHeight) * 0.5,
spinBoxButtonBoxWidth, spinBoxButtonBoxHeight);
if (subControl == SC_SpinBoxDown)
buttonRect.translate(0, spinBoxButtonBoxHeight);
return visualRect(spinBox->direction, frameRect, buttonRect);
}
case SC_SpinBoxEditField: {
auto editRect = adjusted(spinBox->rect, -frameWidth);
if (spinBox->buttonSymbols != QAbstractSpinBox::NoButtons) {
editRect.setWidth(spinBox->rect.width() - frameWidth - spinBoxButtonBoxWidth);
editRect = visualRect(spinBox->direction, spinBox->rect, editRect);
}
return editRect;
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
case CC_ScrollBar:
if (qStyleOptionIs<QStyleOptionSlider>(option)) {
auto scrollBoxStyleOption = qstyleoption_cast<const QStyleOptionSlider *>(option);
auto defaultUpButtonRect = QCommonStyle::subControlRect(control, option, SC_ScrollBarSubLine, widget);
auto defaultDownButtonRect = QCommonStyle::subControlRect(control, option, SC_ScrollBarAddLine, widget);
switch (subControl) {
case SC_ScrollBarAddLine:
case SC_ScrollBarSubLine:
return QRect();
case SC_ScrollBarSubPage: {
auto subPageRect = QCommonStyle::subControlRect(control, option, subControl, widget);
if (scrollBoxStyleOption->orientation == Qt::Vertical)
subPageRect.moveTop(subPageRect.top() - defaultDownButtonRect.height());
else
subPageRect.moveLeft(subPageRect.left() - defaultDownButtonRect.width());
return subPageRect;
}
case SC_ScrollBarAddPage: {
auto addPageRect = QCommonStyle::subControlRect(control, option, subControl, widget);
if (scrollBoxStyleOption->orientation == Qt::Vertical)
addPageRect.moveTop(addPageRect.top() + defaultUpButtonRect.height());
else
addPageRect.moveLeft(addPageRect.left() + defaultUpButtonRect.width());
return addPageRect;
}
case SC_ScrollBarSlider: {
const bool activeScrollBar =
option->state.testFlag(QCommonStyle::State_Enabled)
&& option->state.testFlag(QCommonStyle::State_MouseOver);
auto scrollBarExtent = activeScrollBar ? thickScrollBarSize : thinScrollBarSize;
auto sliderRect = QCommonStyle::subControlRect(control, option, subControl, widget);
if (scrollBoxStyleOption->orientation == Qt::Vertical) {
sliderRect.setWidth(scrollBarExtent);
sliderRect.setHeight(sliderRect.height() + defaultUpButtonRect.height() + defaultDownButtonRect.height());
sliderRect.moveTop(sliderRect.top() - defaultUpButtonRect.height());
sliderRect.moveLeft((option->rect.width() - sliderRect.width()) * 0.5);
} else {
sliderRect.setHeight(scrollBarExtent);
sliderRect.setWidth(sliderRect.width() + defaultUpButtonRect.width() + defaultDownButtonRect.width());
sliderRect.moveTop((option->rect.height() - sliderRect.height()) * 0.5);
sliderRect.moveLeft(sliderRect.left() - defaultUpButtonRect.width());
}
return sliderRect;
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
case CC_GroupBox:
if (qStyleOptionIs<QStyleOptionGroupBox>(option)) {
auto groupBox = *qstyleoption_cast<const QStyleOptionGroupBox *>(option);
groupBox.fontMetrics = QFontMetrics(getGroupBoxTitleFont(widget));
auto labelRect =
QCommonStyle::subControlRect(control, &groupBox, SC_GroupBoxLabel, widget);
if (groupBox.text.isEmpty()) {
labelRect.moveTop(groupBox.rect.top() + groupBoxTopPadding);
labelRect.moveBottom(labelRect.top());
} else {
labelRect.moveTop(
groupBox.rect.top() + groupBoxTopPadding + groupBox.fontMetrics.height() / 2);
}
switch (subControl) {
case SC_GroupBoxFrame:
return QCommonStyle::subControlRect(control, &groupBox, subControl, widget);
case SC_GroupBoxLabel: {
return labelRect;
}
case SC_GroupBoxCheckBox: {
auto checkBoxRect =
QCommonStyle::subControlRect(control, &groupBox, subControl, widget);
checkBoxRect.moveTop(labelRect.center().y() - checkBoxRect.height() / 2);
return checkBoxRect;
}
case SC_GroupBoxContents: {
auto contentsRect =
QCommonStyle::subControlRect(control, &groupBox, SC_GroupBoxContents, widget);
contentsRect.setTop(labelRect.bottom() + (groupBox.text.isEmpty() ? 0 : groupBoxTitleToContentSpacing));
contentsRect.setBottom(groupBox.rect.bottom() - groupBoxBottomPadding);
contentsRect.adjust(groupBoxHorizontalPadding, 0, -groupBoxHorizontalPadding, 0);
return contentsRect;
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
case CC_ComboBox:
if (qStyleOptionIs<QStyleOptionComboBox>(option)) {
auto comboBoxStyleOption = qstyleoption_cast<const QStyleOptionComboBox *>(option);
const auto arrowSize = pixelMetric(PM_MenuButtonIndicator, option, widget);
switch (subControl) {
case SC_ComboBoxFrame: {
return adjusted(comboBoxStyleOption->rect, -comboBoxFocusFrameWidth);;
}
case SC_ComboBoxEditField: {
const auto editFieldRect = comboBoxStyleOption->rect.adjusted(
comboBoxFrameLeftRightPadding, comboBoxVerticalMargin,
-arrowSize - comboBoxFrameLeftRightPadding, -comboBoxVerticalMargin);
return visualRect(comboBoxStyleOption->direction, comboBoxStyleOption->rect, editFieldRect);
}
case SC_ComboBoxArrow: {
auto arrowIconRect = comboBoxStyleOption->rect;
arrowIconRect.setWidth(arrowSize);
arrowIconRect.moveRight(comboBoxStyleOption->rect.right() - comboBoxFrameLeftRightPadding);
return visualRect(comboBoxStyleOption->direction, comboBoxStyleOption->rect, arrowIconRect);
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
case CC_TitleBar:
if (qStyleOptionIs<QStyleOptionTitleBar>(option)) {
auto titleBarOption = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
return visualRect(
titleBarOption->direction, titleBarOption->rect, titleBarSubControlRect(*titleBarOption, subControl));
} else {
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
default:
return QCommonStyle::subControlRect(control, option, subControl, widget);
}
}
QRect QOhosStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
{
switch (element) {
case SE_PushButtonContents:
return option->rect.adjusted(pushButtonHorizontalMargin, 0, -pushButtonHorizontalMargin, 0);
case SE_ItemViewItemFocusRect:
return option->rect.adjusted(focusFrameWidth, focusFrameWidth, -focusFrameWidth, -focusFrameWidth);
case SE_ProgressBarGroove:
case SE_ProgressBarContents:
return option->rect;
case SE_ProgressBarLabel:
return QRect();
case SE_LineEditContents: {
int horizontalMargin =
widget != nullptr && qobjectIsInstanceOf<QAbstractSpinBox>(widget->parent())
? spinBoxEditHorizontalMargin
: lineEditHorizontalMargin;
return option->rect.adjusted(horizontalMargin, 0, -horizontalMargin, 0);
}
case SE_CheckBoxFocusRect:
case SE_RadioButtonFocusRect:
return QRect(
checkBoxOrRadioButtonFocusStrokeWidth, (option->rect.height() - checkBoxOrRadioButtonHoverSize) * 0.5,
checkBoxOrRadioButtonHoverSize, checkBoxOrRadioButtonHoverSize);
case SE_CheckBoxClickRect:
return subElementRect(SE_CheckBoxIndicator, option, widget)
| subElementRect(SE_CheckBoxContents, option, widget);
case SE_RadioButtonClickRect:
return subElementRect(SE_RadioButtonIndicator, option, widget)
| subElementRect(SE_RadioButtonContents, option, widget);
default:
return QCommonStyle::subElementRect(element, option, widget);;
}
}
QSize QOhosStyle::sizeFromContents(
ContentsType contents, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const
{
switch (contents) {
case CT_ItemViewItem: {
const auto viewItemStyleOption = qstyleoption_cast<const QStyleOptionViewItem *>(option);
if (viewItemStyleOption != nullptr) {
if (isItemViewSeparator(viewItemStyleOption->index)) {
return QSize(option->rect.width(), itemViewSeparatorHeight);
} else {
auto verticalMargin = viewItemStyleOption->features.testFlag(QStyleOptionViewItem::HasDecoration)
? itemViewItemWithDecorationVerticalMargin
: itemViewItemVerticalMargin;
return QCommonStyle::sizeFromContents(contents, option, contentsSize, widget)
+ QSize(0, 2 * verticalMargin);
}
} else {
return QCommonStyle::sizeFromContents(contents, option, contentsSize, widget);
}
}
case CT_PushButton: {
auto sizeAlignment = (2 * pushButtonFocusFrameGap) + (2 * pushButtonFocusFrameWidth);
return contentsSize + QSize(
(pushButtonHorizontalMargin * 2) + sizeAlignment, (pushButtonVerticalMargin * 2) + sizeAlignment);
}
case CT_ComboBox: {
const auto arrowSize = pixelMetric(PM_MenuButtonIndicator, option, widget);
auto comboBoxSize = qStyleOptionIs<QStyleOptionComboBox>(option)
&& qstyleoption_cast<const QStyleOptionComboBox *>(option)->editable
? contentsSize + QSize(2 * lineEditHorizontalMargin, 0)
: contentsSize;
const auto frameWidthCompensation = 2 * comboBoxFocusFrameWidth;
comboBoxSize.rwidth() += (arrowSize + frameWidthCompensation + 2 * comboBoxFrameLeftRightPadding);
comboBoxSize.rheight() += (frameWidthCompensation + 2 * comboBoxVerticalMargin + 2 * lineEditVerticalMargin);
return comboBoxSize;
}
case CT_ProgressBar: {
const auto progressBarStyleOption = qstyleoption_cast<const QStyleOptionProgressBar *>(option);
if (progressBarStyleOption != nullptr) {
const bool horizontal = progressBarStyleOption->state & QStyle::State_Horizontal;
if (horizontal)
return QSize(contentsSize.width(), std::max(contentsSize.height(), progressBarMinHeight));
else
return QSize(std::max(contentsSize.height(), progressBarMinHeight), contentsSize.height());
} else {
return QCommonStyle::sizeFromContents(contents, option, contentsSize, widget);
}
}
case CT_MenuItem: {
const auto defaultSize = QCommonStyle::sizeFromContents(contents, option, contentsSize, widget);
const auto *menuItemStyleOption = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
if (menuItemStyleOption != nullptr) {
if (menuItemStyleOption->menuItemType == QStyleOptionMenuItem::Separator) {
return QSize(defaultSize.width(), itemViewSeparatorHeight);
} else {
const auto menuVMargin = pixelMetric(PM_MenuVMargin, option, widget);
const auto arrowWidth = menuItemStyleOption->menuItemType == QStyleOptionMenuItem::SubMenu
? menuVMargin + pixelMetric(PM_SmallIconSize, option, widget)
: 0;
const auto checkboxWidth = menuItemStyleOption->checkType != QStyleOptionMenuItem::NotCheckable
? menuVMargin + pixelMetric(PM_IndicatorWidth, option, widget)
: 0;
return defaultSize
+ QSize(2 * itemViewItemHorizontalMargin, 2 * menuVMargin)
+ QSize(arrowWidth, 0)
+ QSize(checkboxWidth, 0);
}
} else {
return defaultSize;
}
}
case CT_GroupBox: {
const auto groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option);
if (groupBox == nullptr)
return QCommonStyle::sizeFromContents(contents, option, contentsSize, widget);
const QFontMetrics titleMetrics(getGroupBoxTitleFont(widget));
QSize titleSize(
titleMetrics.horizontalAdvance(groupBox->text) + titleMetrics.horizontalAdvance(u' '),
titleMetrics.height());
if (groupBox->subControls.testFlag(SC_GroupBoxCheckBox)) {
titleSize.rwidth() += pixelMetric(PM_IndicatorWidth, option, widget)
+ pixelMetric(PM_CheckBoxLabelSpacing, option, widget);
titleSize.rheight() =
std::max(titleSize.height(), pixelMetric(PM_IndicatorHeight, option, widget));
}
return QCommonStyle::sizeFromContents(contents, option, titleSize, widget);
}
case CT_LineEdit: {
int horizontalMargin;
if (widget != nullptr && qobjectIsInstanceOf<QAbstractSpinBox>(widget->parent()))
horizontalMargin = spinBoxEditHorizontalMargin;
else
horizontalMargin = lineEditHorizontalMargin;
return contentsSize + QSize(horizontalMargin * 2, lineEditVerticalMargin * 2);
}
case CT_SpinBox: {
const auto spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option);
if (spinBox != nullptr) {
int buttonWidth;
if (spinBox->subControls.testFlag(QStyle::SC_SpinBoxUp)
&& spinBox->subControls.testFlag(QStyle::SC_SpinBoxDown)) {
buttonWidth = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxDown, widget).width();
} else {
buttonWidth = 0;
}
const int frameWidth
= spinBox->frame ? pixelMetric(PM_SpinBoxFrameWidth, option, widget) : 0;
return QSize(contentsSize.width() + buttonWidth + 2 * frameWidth + spinBoxEditHorizontalMargin * 2,
std::max(contentsSize.height() + 2 * frameWidth, spinBoxFrameHeight));
}
return contentsSize;
}
default:
return QCommonStyle::sizeFromContents(contents, option, contentsSize, widget);
}
}
int QOhosStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
{
switch (metric) {
case PM_ButtonMargin:
case PM_ButtonDefaultIndicator:
case PM_ButtonShiftHorizontal:
case PM_ButtonShiftVertical:
return 0;
case PM_IndicatorWidth:
case PM_ExclusiveIndicatorWidth:
return checkBoxOrRadioButtonSize;
case PM_IndicatorHeight:
case PM_ExclusiveIndicatorHeight:
return checkBoxOrRadioButtonSize;
case PM_FocusFrameHMargin:
return qStyleOptionIs<QStyleOptionViewItem>(option)
? itemViewItemSpacing
: QCommonStyle::pixelMetric(metric, option, widget);
case PM_TextCursorWidth:
return textCursorWidth;
case PM_DefaultFrameWidth:
if (qobjectIsInstanceOf<QLineEdit>(widget) || qobjectIsInstanceOf<QPushButton>(widget))
return 0;
else
return QCommonStyle::pixelMetric(metric, option, widget);
case PM_MenuBarPanelWidth:
return 0;
case PM_MenuBarItemSpacing:
return menuBarItemSpacing;
case PM_MenuBarVMargin:
return menuBarVerticalMargin;
case PM_MenuBarHMargin:
return menuBarHorizontalMargin;
case PM_MenuPanelWidth:
return 0;
case PM_MenuHMargin:
return 0;
case PM_MenuVMargin:
return menuItemVerticalMargin;
case PM_ProgressBarChunkWidth:
return 0;
case PM_SliderThickness:
return sliderThickness;
case PM_SliderLength:
case PM_SliderControlThickness:
return sliderThumbSize + 2 * sliderHoverSize;
case PM_SmallIconSize:
return qStyleOptionIs<QStyleOptionMenuItem>(option) || qStyleOptionIs<QStyleOptionComboBox>(option)
? smallIconSize
: QCommonStyle::pixelMetric(metric, option, widget);
case PM_SplitterWidth:
return splitterWidth;
case PM_SpinBoxFrameWidth:
return spinBoxFrameStroke;
case PM_ScrollBarExtent:
return maxScrollBarSize;
case PM_TabBarTabShiftVertical:
case PM_TabBarBaseOverlap:
return 0;
case PM_TabBarTabHSpace:
return 2 * tabBarTabRadius + 2 * tabBarTabFrameWidth;
case PM_TitleBarHeight:
return titleBarHeight;
case PM_HeaderMargin:
return headerMargin;
case PM_HeaderDefaultSectionSizeVertical:
return headerDefaultSectionSizeVertical;
case PM_ToolTipLabelFrameWidth:
return toolTipFrameWidth;
case PM_MenuButtonIndicator:
return 2 * QCommonStyle::pixelMetric(metric, option, widget);
default:
return QCommonStyle::pixelMetric(metric, option, widget);
}
}
int QOhosStyle::styleHint(
StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *hintReturn) const
{
switch (hint) {
case SH_Slider_AbsoluteSetButtons:
return Qt::LeftButton | Qt::MiddleButton;
case SH_Slider_PageSetButtons:
return 0;
case SH_ItemView_ShowDecorationSelected:
return qobjectIsInstanceOf<QTreeView>(widget) ? 0 : 1;
case SH_ToolTipLabel_Opacity:
return toolTipBackgroundAlpha;
case SH_Menu_MouseTracking:
case SH_MenuBar_MouseTracking:
return 1;
default:
return QCommonStyle::styleHint(hint, option, widget, hintReturn);
}
}
void QOhosStyle::polish(QWidget *widget)
{
QCommonStyle::polish(widget);
if (isHoverable(widget))
widget->setAttribute(Qt::WA_Hover);
if (qobjectIsInstanceOf<QPushButton>(widget)) {
if (qobject_cast<QPushButton *>(widget)->isDefault()) {
QPalette palette = widget->palette();
auto textDisabledColor = palette.color(QPalette::Active, QPalette::Base);
textDisabledColor.setAlphaF(ohos_id_alpha_disabled);
palette.setColor(QPalette::All, QPalette::ButtonText, palette.color(QPalette::Active, QPalette::Base));
palette.setColor(QPalette::Disabled, QPalette::ButtonText, textDisabledColor);
widget->setPalette(palette);
}
} else if (qobjectIsInstanceOf<QScrollBar>(widget)) {
widget->setAttribute(Qt::WA_NoSystemBackground);
widget->setAttribute(Qt::WA_OpaquePaintEvent, false);
} else if (qobjectIsInstanceOf<QListView>(widget)) {
qobject_cast<QListView *>(widget)->viewport()->setAttribute(Qt::WA_Hover);
} else if (qobjectIsInstanceOf<QComboBox>(widget)) {
auto comboBox = qobject_cast<QComboBox *>(widget);
const char *delegateClassName = comboBox->itemDelegate()->metaObject()->className();
bool isDefaultComboBoxDelegate =
qstrcmp(delegateClassName, "QComboBoxDelegate") == 0
|| qstrcmp(delegateClassName, "QComboMenuDelegate") == 0;
if (isDefaultComboBoxDelegate)
comboBox->setItemDelegate(new QStyledItemDelegate(comboBox->view()));
} else if (qobjectIsInstanceOf<QMdiSubWindow>(widget)) {
widget->setAttribute(Qt::WA_TranslucentBackground);
widget->setAutoFillBackground(false);
auto palette = widget->palette();
palette.setColor(QPalette::Highlight, palette.color(QPalette::Active, QPalette::Base));
palette.setColor(QPalette::Inactive, QPalette::Dark, palette.color(QPalette::Inactive, QPalette::Base));
palette.setColor(
QPalette::Inactive, QPalette::Window,
makeInactiveOrDisabledFromColor(palette.color(QPalette::Active, QPalette::AlternateBase)));
palette.setColor(QPalette::HighlightedText, Qt::black);
widget->setPalette(palette);
}
}
void QOhosStyle::unpolish(QWidget *widget)
{
if (isHoverable(widget)) {
widget->setAttribute(Qt::WA_Hover, false);
} else if (qobjectIsInstanceOf<QScrollBar>(widget)) {
widget->setAttribute(Qt::WA_NoSystemBackground, false);
widget->setAttribute(Qt::WA_OpaquePaintEvent);
} else if (qobjectIsInstanceOf<QListView>(widget)) {
qobject_cast<QListView *>(widget)->viewport()->setAttribute(Qt::WA_Hover, false);
}
QCommonStyle::unpolish(widget);
}
QPalette QOhosStyle::standardPalette() const
{
return *QGuiApplicationPrivate::platformTheme()->palette();
}
QIcon QOhosStyle::standardIcon(
StandardPixmap standardPixmap, const QStyleOption *option, const QWidget *widget) const
{
const QString iconName = ohosThemeIconName(standardPixmap);
if (!iconName.isEmpty()) {
const QIcon icon = QIcon::fromTheme(iconName);
if (!icon.isNull())
return icon;
}
return QCommonStyle::standardIcon(standardPixmap, option, widget);
}