forked from openkylin/qt5-ukui-platformtheme
1908 lines
75 KiB
C++
1908 lines
75 KiB
C++
/*
|
|
* Qt5-UKUI's Library
|
|
*
|
|
* Copyright (C) 2023, KylinSoft Co., Ltd.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this library. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Authors: Yan Wang <wangyan@kylinos.cn>
|
|
*
|
|
*/
|
|
|
|
#include "kyquickstyleitem.h"
|
|
|
|
#include <QStyle>
|
|
#include <QStyleFactory>
|
|
#include <QStyleOption>
|
|
#include <QApplication>
|
|
#include <QSGNinePatchNode>
|
|
#include <QPainter>
|
|
#include <QPixmapCache>
|
|
#include <QStringBuilder>
|
|
#include <QQuickWindow>
|
|
|
|
#include <KSharedConfig>
|
|
#include <KConfigGroup>
|
|
#include <QGSettings/QGSettings>
|
|
#include <QApplication>
|
|
|
|
|
|
QStyle *KyQuickStyleItem::s_style = nullptr;
|
|
|
|
QStyle *KyQuickStyleItem::style()
|
|
{
|
|
auto style = qApp->style();
|
|
return style ? style : s_style;
|
|
}
|
|
|
|
KyQuickStyleItem::KyQuickStyleItem(QQuickItem *parent)
|
|
: QQuickItem(parent),
|
|
m_styleoption(nullptr),
|
|
m_itemType(Undefined),
|
|
m_sunken(false),
|
|
m_raised(false),
|
|
m_active(true),
|
|
m_selected(false),
|
|
m_focus(false),
|
|
m_hover(false),
|
|
m_on(false),
|
|
m_horizontal(true),
|
|
m_transient(false),
|
|
m_sharedWidget(false),
|
|
m_minimum(0),
|
|
m_maximum(100),
|
|
m_value(0),
|
|
m_step(0),
|
|
m_paintMargins(0),
|
|
m_contentWidth(0),
|
|
m_contentHeight(0),
|
|
m_textureWidth(0),
|
|
m_textureHeight(0),
|
|
m_lastFocusReason(Qt::NoFocusReason)
|
|
{
|
|
// There is no styleChanged signal and QApplication sends QEvent::StyleChange only to all QWidgets
|
|
if (qApp->style()) {
|
|
connect(qApp->style(), &QObject::destroyed, this, &KyQuickStyleItem::styleChanged);
|
|
} else {
|
|
KSharedConfig::Ptr kdeglobals = KSharedConfig::openConfig();
|
|
KConfigGroup cg(kdeglobals, "KDE");
|
|
auto style = s_style;
|
|
s_style = QStyleFactory::create(cg.readEntry("widgetStyle", QStringLiteral("Fusion")));
|
|
if (style) {
|
|
delete style;
|
|
}
|
|
}
|
|
|
|
if (QGSettings::isSchemaInstalled("org.ukui.style")) {
|
|
QGSettings* styleSettings = new QGSettings("org.ukui.style", QByteArray(), this);
|
|
connect(styleSettings, &QGSettings::changed, this, [&](const QString &key){
|
|
if (key == "systemFontSize" || key == "systemFont") {
|
|
emit fontChanged();
|
|
updatePolish();
|
|
}
|
|
if (key == "iconThemeName"){
|
|
polish();
|
|
}
|
|
});
|
|
}
|
|
|
|
m_font = qApp->font();
|
|
setFlag(QQuickItem::ItemHasContents, true);
|
|
setSmooth(false);
|
|
|
|
connect(this, &KyQuickStyleItem::visibleChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::widthChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::heightChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::enabledChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::infoChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::onChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::selectedChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::activeChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::textChanged, this, &KyQuickStyleItem::updateSizeHint);
|
|
connect(this, &KyQuickStyleItem::textChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::activeChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::raisedChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::sunkenChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::hoverChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::maximumChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::minimumChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::valueChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::horizontalChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::transientChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::activeControlChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::hasFocusChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::activeControlChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::hintChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::propertiesChanged, this, &KyQuickStyleItem::updateSizeHint);
|
|
connect(this, &KyQuickStyleItem::propertiesChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::elementTypeChanged, this, &KyQuickStyleItem::updateItem);
|
|
connect(this, &KyQuickStyleItem::contentWidthChanged, this, &KyQuickStyleItem::updateSizeHint);
|
|
connect(this, &KyQuickStyleItem::contentHeightChanged, this, &KyQuickStyleItem::updateSizeHint);
|
|
connect(this, &KyQuickStyleItem::widthChanged, this, &KyQuickStyleItem::updateRect);
|
|
connect(this, &KyQuickStyleItem::heightChanged, this, &KyQuickStyleItem::updateRect);
|
|
|
|
connect(this, &KyQuickStyleItem::heightChanged, this, &KyQuickStyleItem::updateBaselineOffset);
|
|
connect(this, &KyQuickStyleItem::contentHeightChanged, this, &KyQuickStyleItem::updateBaselineOffset);
|
|
|
|
connect(qApp, &QApplication::fontChanged, this, &KyQuickStyleItem::updateSizeHint, Qt::QueuedConnection);
|
|
}
|
|
|
|
KyQuickStyleItem::~KyQuickStyleItem()
|
|
{
|
|
if (const QStyleOptionButton *aux = qstyleoption_cast<const QStyleOptionButton*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionViewItem *aux = qstyleoption_cast<const QStyleOptionViewItem*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionHeader *aux = qstyleoption_cast<const QStyleOptionHeader*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionToolButton *aux = qstyleoption_cast<const QStyleOptionToolButton*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionToolBar *aux = qstyleoption_cast<const QStyleOptionToolBar*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionTab *aux = qstyleoption_cast<const QStyleOptionTab*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionFrame *aux = qstyleoption_cast<const QStyleOptionFrame*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionFocusRect *aux = qstyleoption_cast<const QStyleOptionFocusRect*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionTabWidgetFrame *aux = qstyleoption_cast<const QStyleOptionTabWidgetFrame*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionMenuItem *aux = qstyleoption_cast<const QStyleOptionMenuItem*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionComboBox *aux = qstyleoption_cast<const QStyleOptionComboBox*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionSpinBox *aux = qstyleoption_cast<const QStyleOptionSpinBox*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionSlider *aux = qstyleoption_cast<const QStyleOptionSlider*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionProgressBar *aux = qstyleoption_cast<const QStyleOptionProgressBar*>(m_styleoption))
|
|
delete aux;
|
|
else if (const QStyleOptionGroupBox *aux = qstyleoption_cast<const QStyleOptionGroupBox*>(m_styleoption))
|
|
delete aux;
|
|
else
|
|
delete m_styleoption;
|
|
|
|
m_styleoption = nullptr;
|
|
}
|
|
|
|
void KyQuickStyleItem::initStyleOption()
|
|
{
|
|
if (m_styleoption)
|
|
m_styleoption->state = {};
|
|
|
|
QString sizeHint = m_hints.value(QStringLiteral("size")).toString();
|
|
|
|
bool needsResolvePalette = true;
|
|
update();
|
|
|
|
switch (m_itemType) {
|
|
case Button: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionButton();
|
|
|
|
QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(m_styleoption);
|
|
opt->text = text();
|
|
|
|
const QVariant icon = m_properties[QStringLiteral("icon")];
|
|
if (icon.canConvert<QIcon>()) {
|
|
opt->icon = icon.value<QIcon>();
|
|
} else if (icon.canConvert<QUrl>() && icon.value<QUrl>().isLocalFile()) {
|
|
opt->icon = QIcon(icon.value<QUrl>().toLocalFile());
|
|
} else if (icon.canConvert<QString>()) {
|
|
opt->icon = QIcon::fromTheme(icon.value<QString>());
|
|
}
|
|
auto iconSize = QSize(m_properties[QStringLiteral("iconWidth")].toInt(),
|
|
m_properties[QStringLiteral("iconHeight")].toInt());
|
|
if (iconSize.isEmpty()) {
|
|
int e = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ButtonIconSize, m_styleoption, nullptr);
|
|
if (iconSize.width() <= 0) {
|
|
iconSize.setWidth(e);
|
|
}
|
|
if (iconSize.height() <= 0) {
|
|
iconSize.setHeight(e);
|
|
}
|
|
}
|
|
opt->iconSize = iconSize;
|
|
opt->features = activeControl() == QLatin1String("default") ?
|
|
QStyleOptionButton::DefaultButton :
|
|
QStyleOptionButton::None;
|
|
if (m_properties[QStringLiteral("flat")].toBool()) {
|
|
opt->features |= QStyleOptionButton::Flat;
|
|
}
|
|
const QFont font = qApp->font("QPushButton");
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
QObject * menu = m_properties[QStringLiteral("menu")].value<QObject *>();
|
|
if (menu) {
|
|
opt->features |= QStyleOptionButton::HasMenu;
|
|
}
|
|
}
|
|
break;
|
|
case ItemRow: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionViewItem();
|
|
|
|
QStyleOptionViewItem *opt = qstyleoption_cast<QStyleOptionViewItem*>(m_styleoption);
|
|
opt->features = {};
|
|
if (activeControl() == QLatin1String("alternate"))
|
|
opt->features |= QStyleOptionViewItem::Alternate;
|
|
}
|
|
break;
|
|
|
|
case Splitter: {
|
|
if (!m_styleoption) {
|
|
m_styleoption = new QStyleOption;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case Item: {
|
|
if (!m_styleoption) {
|
|
m_styleoption = new QStyleOptionViewItem();
|
|
}
|
|
QStyleOptionViewItem *opt = qstyleoption_cast<QStyleOptionViewItem*>(m_styleoption);
|
|
opt->features = QStyleOptionViewItem::HasDisplay;
|
|
opt->text = text();
|
|
opt->textElideMode = Qt::ElideRight;
|
|
opt->displayAlignment = Qt::AlignLeft | Qt::AlignVCenter;
|
|
opt->decorationAlignment = Qt::AlignCenter;
|
|
resolvePalette();
|
|
needsResolvePalette = false;
|
|
QPalette pal = m_styleoption->palette;
|
|
pal.setBrush(QPalette::Base, Qt::NoBrush);
|
|
m_styleoption->palette = pal;
|
|
const QFont font = qApp->font("QAbstractItemView");
|
|
opt->font = font;
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
break;
|
|
}
|
|
case ItemBranchIndicator: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOption;
|
|
|
|
m_styleoption->state = QStyle::State_Item; // We don't want to fully support Win 95
|
|
if (m_properties.value(QStringLiteral("hasChildren")).toBool())
|
|
m_styleoption->state |= QStyle::State_Children;
|
|
if (m_properties.value(QStringLiteral("hasSibling")).toBool()) // Even this one could go away
|
|
m_styleoption->state |= QStyle::State_Sibling;
|
|
if (m_on)
|
|
m_styleoption->state |= QStyle::State_Open;
|
|
}
|
|
break;
|
|
case Header: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionHeader();
|
|
|
|
QStyleOptionHeader *opt = qstyleoption_cast<QStyleOptionHeader*>(m_styleoption);
|
|
opt->text = text();
|
|
opt->textAlignment = static_cast<Qt::AlignmentFlag>(m_properties.value(QStringLiteral("textalignment")).toInt());
|
|
opt->sortIndicator = activeControl() == QLatin1String("down") ?
|
|
QStyleOptionHeader::SortDown
|
|
: activeControl() == QLatin1String("up") ?
|
|
QStyleOptionHeader::SortUp : QStyleOptionHeader::None;
|
|
QString headerpos = m_properties.value(QStringLiteral("headerpos")).toString();
|
|
if (headerpos == QLatin1String("beginning"))
|
|
opt->position = QStyleOptionHeader::Beginning;
|
|
else if (headerpos == QLatin1String("end"))
|
|
opt->position = QStyleOptionHeader::End;
|
|
else if (headerpos == QLatin1String("only"))
|
|
opt->position = QStyleOptionHeader::OnlyOneSection;
|
|
else
|
|
opt->position = QStyleOptionHeader::Middle;
|
|
|
|
const QFont font = qApp->font("QHeaderView");
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
}
|
|
break;
|
|
case ToolButton: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionToolButton();
|
|
|
|
QStyleOptionToolButton *opt =
|
|
qstyleoption_cast<QStyleOptionToolButton*>(m_styleoption);
|
|
opt->subControls = QStyle::SC_ToolButton;
|
|
opt->state |= QStyle::State_AutoRaise;
|
|
opt->activeSubControls = QStyle::SC_ToolButton;
|
|
opt->text = text();
|
|
|
|
const QVariant icon = m_properties[QStringLiteral("icon")];
|
|
if (icon.canConvert<QIcon>()) {
|
|
opt->icon = icon.value<QIcon>();
|
|
} else if (icon.canConvert<QUrl>() && icon.value<QUrl>().isLocalFile()) {
|
|
opt->icon = QIcon(icon.value<QUrl>().toLocalFile());
|
|
} else if (icon.canConvert<QString>()) {
|
|
opt->icon = QIcon::fromTheme(icon.value<QString>());
|
|
}
|
|
auto iconSize = QSize(m_properties[QStringLiteral("iconWidth")].toInt(),
|
|
m_properties[QStringLiteral("iconHeight")].toInt());
|
|
if (iconSize.isEmpty()) {
|
|
int e = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ToolBarIconSize, m_styleoption, nullptr);
|
|
if (iconSize.width() <= 0) {
|
|
iconSize.setWidth(e);
|
|
}
|
|
if (iconSize.height() <= 0) {
|
|
iconSize.setHeight(e);
|
|
}
|
|
}
|
|
opt->iconSize = iconSize;
|
|
|
|
if (m_properties.value(QStringLiteral("menu")).toBool()) {
|
|
opt->subControls |= QStyle::SC_ToolButtonMenu;
|
|
opt->features = QStyleOptionToolButton::HasMenu;
|
|
}
|
|
|
|
const int toolButtonStyle = m_properties.value(QStringLiteral("toolButtonStyle")).toInt();
|
|
|
|
switch (toolButtonStyle) {
|
|
case Qt::ToolButtonIconOnly:
|
|
case Qt::ToolButtonTextOnly:
|
|
case Qt::ToolButtonTextBesideIcon:
|
|
case Qt::ToolButtonTextUnderIcon:
|
|
case Qt::ToolButtonFollowStyle:
|
|
opt->toolButtonStyle = (Qt::ToolButtonStyle)toolButtonStyle;
|
|
break;
|
|
default:
|
|
opt->toolButtonStyle = Qt::ToolButtonFollowStyle;
|
|
}
|
|
|
|
const QFont font = qApp->font("QToolButton");
|
|
opt->font = font;
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
}
|
|
break;
|
|
case ToolBar: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionToolBar();
|
|
}
|
|
break;
|
|
case Tab: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionTab();
|
|
|
|
QStyleOptionTab *opt = qstyleoption_cast<QStyleOptionTab*>(m_styleoption);
|
|
opt->text = text();
|
|
|
|
const QVariant icon = m_properties[QStringLiteral("icon")];
|
|
if (icon.canConvert<QIcon>()) {
|
|
opt->icon = icon.value<QIcon>();
|
|
} else if (icon.canConvert<QUrl>() && icon.value<QUrl>().isLocalFile()) {
|
|
opt->icon = QIcon(icon.value<QUrl>().toLocalFile());
|
|
} else if (icon.canConvert<QString>()) {
|
|
opt->icon = QIcon::fromTheme(icon.value<QString>());
|
|
}
|
|
auto iconSize = QSize(m_properties[QStringLiteral("iconWidth")].toInt(),
|
|
m_properties[QStringLiteral("iconHeight")].toInt());
|
|
if (iconSize.isEmpty()) {
|
|
int e = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ButtonIconSize, m_styleoption, nullptr);
|
|
if (iconSize.width() <= 0) {
|
|
iconSize.setWidth(e);
|
|
}
|
|
if (iconSize.height() <= 0) {
|
|
iconSize.setHeight(e);
|
|
}
|
|
}
|
|
opt->iconSize = iconSize;
|
|
|
|
if (m_properties.value(QStringLiteral("hasFrame")).toBool())
|
|
opt->features |= QStyleOptionTab::HasFrame;
|
|
|
|
QString orientation = m_properties.value(QStringLiteral("orientation")).toString();
|
|
QString position = m_properties.value(QStringLiteral("tabpos")).toString();
|
|
QString selectedPosition = m_properties.value(QStringLiteral("selectedpos")).toString();
|
|
|
|
opt->shape = orientation == QLatin1String("Bottom") ? QTabBar::RoundedSouth : QTabBar::RoundedNorth;
|
|
if (position == QLatin1String("beginning"))
|
|
opt->position = QStyleOptionTab::Beginning;
|
|
else if (position == QLatin1String("end"))
|
|
opt->position = QStyleOptionTab::End;
|
|
else if (position == QLatin1String("only"))
|
|
opt->position = QStyleOptionTab::OnlyOneTab;
|
|
else
|
|
opt->position = QStyleOptionTab::Middle;
|
|
|
|
if (selectedPosition == QLatin1String("next"))
|
|
opt->selectedPosition = QStyleOptionTab::NextIsSelected;
|
|
else if (selectedPosition == QLatin1String("previous"))
|
|
opt->selectedPosition = QStyleOptionTab::PreviousIsSelected;
|
|
else
|
|
opt->selectedPosition = QStyleOptionTab::NotAdjacent;
|
|
|
|
|
|
} break;
|
|
|
|
case Frame: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionFrame();
|
|
|
|
QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(m_styleoption);
|
|
opt->frameShape = QFrame::StyledPanel;
|
|
opt->lineWidth = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, nullptr);
|
|
opt->midLineWidth = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, nullptr);
|
|
}
|
|
break;
|
|
case FocusRect: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionFocusRect();
|
|
// Needed on windows
|
|
m_styleoption->state |= QStyle::State_KeyboardFocusChange;
|
|
}
|
|
break;
|
|
case TabFrame: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionTabWidgetFrame();
|
|
QStyleOptionTabWidgetFrame *opt = qstyleoption_cast<QStyleOptionTabWidgetFrame*>(m_styleoption);
|
|
|
|
opt->selectedTabRect = m_properties[QStringLiteral("selectedTabRect")].toRect();
|
|
opt->shape = m_properties[QStringLiteral("orientation")] == Qt::BottomEdge ? QTabBar::RoundedSouth : QTabBar::RoundedNorth;
|
|
if (minimum())
|
|
opt->selectedTabRect = QRect(value(), 0, minimum(), height());
|
|
opt->tabBarSize = QSize(minimum() , height());
|
|
// oxygen style needs this hack
|
|
opt->leftCornerWidgetSize = QSize(value(), 0);
|
|
}
|
|
break;
|
|
case MenuBar:
|
|
if (!m_styleoption) {
|
|
QStyleOptionMenuItem *menuOpt = new QStyleOptionMenuItem();
|
|
menuOpt->menuItemType = QStyleOptionMenuItem::EmptyArea;
|
|
m_styleoption = menuOpt;
|
|
}
|
|
|
|
break;
|
|
case MenuBarItem:
|
|
{
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionMenuItem();
|
|
|
|
QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(m_styleoption);
|
|
opt->text = text();
|
|
opt->menuItemType = QStyleOptionMenuItem::Normal;
|
|
setProperty("_q_showUnderlined", m_hints[QStringLiteral("showUnderlined")].toBool());
|
|
|
|
const QFont font = qApp->font("QMenuBar");
|
|
opt->font = font;
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
m_font = opt->font;
|
|
}
|
|
break;
|
|
case Menu: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionMenuItem();
|
|
}
|
|
break;
|
|
case MenuItem:
|
|
case ComboBoxItem:
|
|
{
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionMenuItem();
|
|
|
|
QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(m_styleoption);
|
|
// For GTK style. See below, in setElementType()
|
|
setProperty("_q_isComboBoxPopupItem", m_itemType == ComboBoxItem);
|
|
|
|
KyQuickStyleItem::MenuItemType type =
|
|
static_cast<KyQuickStyleItem::MenuItemType>(m_properties[QStringLiteral("type")].toInt());
|
|
if (type == KyQuickStyleItem::ScrollIndicatorType) {
|
|
int scrollerDirection = m_properties[QStringLiteral("scrollerDirection")].toInt();
|
|
opt->menuItemType = QStyleOptionMenuItem::Scroller;
|
|
opt->state |= scrollerDirection == Qt::UpArrow ?
|
|
QStyle::State_UpArrow : QStyle::State_DownArrow;
|
|
} else if (type == KyQuickStyleItem::SeparatorType) {
|
|
opt->menuItemType = QStyleOptionMenuItem::Separator;
|
|
} else {
|
|
opt->text = text();
|
|
|
|
if (type == KyQuickStyleItem::MenuType) {
|
|
opt->menuItemType = QStyleOptionMenuItem::SubMenu;
|
|
} else {
|
|
opt->menuItemType = QStyleOptionMenuItem::Normal;
|
|
|
|
QString shortcut = m_properties[QStringLiteral("shortcut")].toString();
|
|
if (!shortcut.isEmpty()) {
|
|
opt->text += QLatin1Char('\t') + shortcut;
|
|
opt->tabWidth = qMax(opt->tabWidth, qRound(textWidth(shortcut)));
|
|
}
|
|
|
|
if (m_properties[QStringLiteral("checkable")].toBool()) {
|
|
opt->checked = on();
|
|
QVariant exclusive = m_properties[QStringLiteral("exclusive")];
|
|
opt->checkType = exclusive.toBool() ? QStyleOptionMenuItem::Exclusive :
|
|
QStyleOptionMenuItem::NonExclusive;
|
|
}
|
|
}
|
|
if (m_properties[QStringLiteral("icon")].canConvert<QIcon>())
|
|
opt->icon = m_properties[QStringLiteral("icon")].value<QIcon>();
|
|
setProperty("_q_showUnderlined", m_hints[QStringLiteral("showUnderlined")].toBool());
|
|
|
|
const QFont font = qApp->font(m_itemType == ComboBoxItem ?"QComboMenuItem" : "QMenu");
|
|
opt->font = font;
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
m_font = opt->font;
|
|
}
|
|
}
|
|
break;
|
|
case CheckBox:
|
|
case RadioButton:
|
|
{
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionButton();
|
|
|
|
QStyleOptionButton *opt = qstyleoption_cast<QStyleOptionButton*>(m_styleoption);
|
|
if (!on())
|
|
opt->state |= QStyle::State_Off;
|
|
if (m_properties.value(QStringLiteral("partiallyChecked")).toBool())
|
|
opt->state |= QStyle::State_NoChange;
|
|
opt->text = text();
|
|
}
|
|
break;
|
|
case Edit: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionFrame();
|
|
|
|
QStyleOptionFrame *opt = qstyleoption_cast<QStyleOptionFrame*>(m_styleoption);
|
|
opt->lineWidth = qMax(1, KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, nullptr)); //this must be non zero
|
|
}
|
|
break;
|
|
case ComboBox :{
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionComboBox();
|
|
|
|
QStyleOptionComboBox *opt = qstyleoption_cast<QStyleOptionComboBox*>(m_styleoption);
|
|
|
|
const QFont font = qApp->font("QPushButton"); //DAVE - QQC1 code does this, but if you look at QComboBox this doesn't make sense
|
|
opt->fontMetrics = QFontMetrics(font);
|
|
opt->currentText = text();
|
|
opt->editable = m_properties[QStringLiteral("editable")].toBool();
|
|
|
|
const QVariant icon = m_properties[QStringLiteral("currentIcon")];
|
|
if (icon.canConvert<QIcon>()) {
|
|
opt->currentIcon = icon.value<QIcon>();
|
|
} else if (icon.canConvert<QString>()) {
|
|
opt->currentIcon = QIcon::fromTheme(icon.value<QString>());
|
|
}
|
|
auto iconSize = QSize(m_properties[QStringLiteral("iconWidth")].toInt(),
|
|
m_properties[QStringLiteral("iconHeight")].toInt());
|
|
if (iconSize.isEmpty()) {
|
|
int e = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ButtonIconSize, m_styleoption, nullptr);
|
|
if (iconSize.width() <= 0) {
|
|
iconSize.setWidth(e);
|
|
}
|
|
if (iconSize.height() <= 0) {
|
|
iconSize.setHeight(e);
|
|
}
|
|
}
|
|
opt->iconSize = iconSize;
|
|
}
|
|
break;
|
|
case SpinBox: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionSpinBox();
|
|
|
|
QStyleOptionSpinBox *opt = qstyleoption_cast<QStyleOptionSpinBox*>(m_styleoption);
|
|
opt->frame = true;
|
|
opt->subControls = QStyle::SC_SpinBoxFrame | QStyle::SC_SpinBoxEditField;
|
|
if (value() & 0x1)
|
|
opt->activeSubControls = QStyle::SC_SpinBoxUp;
|
|
else if (value() & (1<<1))
|
|
opt->activeSubControls = QStyle::SC_SpinBoxDown;
|
|
opt->subControls = QStyle::SC_All;
|
|
opt->stepEnabled = {};
|
|
if (value() & (1<<2))
|
|
opt->stepEnabled |= QAbstractSpinBox::StepUpEnabled;
|
|
if (value() & (1<<3))
|
|
opt->stepEnabled |= QAbstractSpinBox::StepDownEnabled;
|
|
}
|
|
break;
|
|
case Slider:
|
|
case Dial:
|
|
{
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionSlider();
|
|
|
|
QStyleOptionSlider *opt = qstyleoption_cast<QStyleOptionSlider*>(m_styleoption);
|
|
opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical;
|
|
opt->upsideDown = !horizontal();
|
|
|
|
int min = minimum();
|
|
int max = std::max(min, maximum());
|
|
|
|
opt->minimum = min;
|
|
opt->maximum = max;
|
|
opt->sliderPosition = value();
|
|
opt->singleStep = step();
|
|
|
|
if (opt->singleStep) {
|
|
qreal numOfSteps = (opt->maximum - opt->minimum) / opt->singleStep;
|
|
// at least 5 pixels between tick marks
|
|
qreal extent = horizontal() ? width() : height();
|
|
if (numOfSteps && (extent / numOfSteps < 5))
|
|
opt->tickInterval = qRound((5 * numOfSteps / extent) + 0.5) * step();
|
|
else
|
|
opt->tickInterval = opt->singleStep;
|
|
|
|
} else // default Qt-components implementation
|
|
opt->tickInterval = opt->maximum != opt->minimum ? 1200 / (opt->maximum - opt->minimum) : 0;
|
|
|
|
opt->sliderValue = value();
|
|
opt->subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
|
|
opt->tickPosition = activeControl() == QLatin1String("ticks") ?
|
|
QSlider::TicksBelow : QSlider::NoTicks;
|
|
if (opt->tickPosition != QSlider::NoTicks)
|
|
opt->subControls |= QStyle::SC_SliderTickmarks;
|
|
|
|
opt->activeSubControls = QStyle::SC_SliderHandle;
|
|
}
|
|
break;
|
|
case ProgressBar: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionProgressBar();
|
|
|
|
QStyleOptionProgressBar *opt = qstyleoption_cast<QStyleOptionProgressBar*>(m_styleoption);
|
|
opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical;
|
|
opt->minimum = qMax(0, minimum());
|
|
opt->maximum = qMax(0, maximum());
|
|
opt->progress = value();
|
|
}
|
|
break;
|
|
case GroupBox: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionGroupBox();
|
|
|
|
QStyleOptionGroupBox *opt = qstyleoption_cast<QStyleOptionGroupBox*>(m_styleoption);
|
|
opt->text = text();
|
|
opt->lineWidth = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, nullptr);
|
|
opt->subControls = QStyle::SC_GroupBoxLabel;
|
|
opt->features = {};
|
|
if (m_properties[QStringLiteral("sunken")].toBool()) { // Qt draws an ugly line here so I ignore it
|
|
opt->subControls |= QStyle::SC_GroupBoxFrame;
|
|
} else {
|
|
opt->features |= QStyleOptionFrame::Flat;
|
|
}
|
|
if (m_properties[QStringLiteral("checkable")].toBool())
|
|
opt->subControls |= QStyle::SC_GroupBoxCheckBox;
|
|
|
|
}
|
|
break;
|
|
case ScrollBar: {
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOptionSlider();
|
|
|
|
QStyleOptionSlider *opt = qstyleoption_cast<QStyleOptionSlider*>(m_styleoption);
|
|
opt->minimum = qMax(0, minimum());
|
|
opt->maximum = qMax(0, maximum());
|
|
opt->pageStep = qMax(0, int(horizontal() ? width() : height()));
|
|
opt->orientation = horizontal() ? Qt::Horizontal : Qt::Vertical;
|
|
opt->sliderPosition = value();
|
|
opt->sliderValue = value();
|
|
opt->activeSubControls = (activeControl() == QLatin1String("up"))
|
|
? QStyle::SC_ScrollBarSubLine : (activeControl() == QLatin1String("down")) ?
|
|
QStyle::SC_ScrollBarAddLine :
|
|
(activeControl() == QLatin1String("handle")) ?
|
|
QStyle::SC_ScrollBarSlider : hover() ? QStyle::SC_ScrollBarGroove : QStyle::SC_None;
|
|
if (raised())
|
|
opt->state |= QStyle::State_On;
|
|
|
|
opt->sliderValue = value();
|
|
opt->subControls = QStyle::SC_All;
|
|
|
|
setTransient(KyQuickStyleItem::style()->styleHint(QStyle::SH_ScrollBar_Transient, m_styleoption));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!m_styleoption)
|
|
m_styleoption = new QStyleOption();
|
|
|
|
if (needsResolvePalette)
|
|
resolvePalette();
|
|
|
|
m_styleoption->styleObject = this;
|
|
m_styleoption->direction = qApp->layoutDirection();
|
|
|
|
int w = m_textureWidth > 0 ? m_textureWidth : width();
|
|
int h = m_textureHeight > 0 ? m_textureHeight : height();
|
|
|
|
m_styleoption->rect = QRect(m_paintMargins, 0, w - 2* m_paintMargins, h);
|
|
|
|
if (isEnabled()) {
|
|
m_styleoption->state |= QStyle::State_Enabled;
|
|
m_styleoption->palette.setCurrentColorGroup(QPalette::Active);
|
|
} else {
|
|
m_styleoption->palette.setCurrentColorGroup(QPalette::Disabled);
|
|
}
|
|
if (m_active)
|
|
m_styleoption->state |= QStyle::State_Active;
|
|
else
|
|
m_styleoption->palette.setCurrentColorGroup(QPalette::Inactive);
|
|
if (m_sunken)
|
|
m_styleoption->state |= QStyle::State_Sunken;
|
|
if (m_raised)
|
|
m_styleoption->state |= QStyle::State_Raised;
|
|
if (m_selected)
|
|
m_styleoption->state |= QStyle::State_Selected;
|
|
if (m_focus)
|
|
m_styleoption->state |= QStyle::State_HasFocus;
|
|
if (m_on)
|
|
m_styleoption->state |= QStyle::State_On;
|
|
if (m_hover)
|
|
m_styleoption->state |= QStyle::State_MouseOver;
|
|
if (m_horizontal)
|
|
m_styleoption->state |= QStyle::State_Horizontal;
|
|
|
|
// some styles don't draw a focus rectangle if
|
|
// QStyle::State_KeyboardFocusChange is not set
|
|
if (window()) {
|
|
if (m_lastFocusReason == Qt::TabFocusReason || m_lastFocusReason == Qt::BacktabFocusReason) {
|
|
m_styleoption->state |= QStyle::State_KeyboardFocusChange;
|
|
}
|
|
}
|
|
|
|
if (sizeHint == QLatin1String("mini")) {
|
|
m_styleoption->state |= QStyle::State_Mini;
|
|
} else if (sizeHint == QLatin1String("small")) {
|
|
m_styleoption->state |= QStyle::State_Small;
|
|
}
|
|
|
|
}
|
|
|
|
const char* KyQuickStyleItem::classNameForItem() const
|
|
{
|
|
switch(m_itemType) {
|
|
case Button:
|
|
return "QPushButton";
|
|
case RadioButton:
|
|
return "QRadioButton";
|
|
case CheckBox:
|
|
return "QCheckBox";
|
|
case ComboBox:
|
|
return "QComboBox";
|
|
case ComboBoxItem:
|
|
return "QComboMenuItem";
|
|
case ToolBar:
|
|
return "";
|
|
case ToolButton:
|
|
return "QToolButton";
|
|
case Tab:
|
|
return "QTabButton";
|
|
case TabFrame:
|
|
return "QTabBar";
|
|
case Edit:
|
|
return "QTextEdit";
|
|
case GroupBox:
|
|
return "QGroupBox";
|
|
case Header:
|
|
return "QHeaderView";
|
|
case Item:
|
|
case ItemRow:
|
|
return "QAbstractItemView";
|
|
case Menu:
|
|
case MenuItem:
|
|
return "QMenu";
|
|
case MenuBar:
|
|
case MenuBarItem:
|
|
return "QMenuBar";
|
|
default:
|
|
return "";
|
|
}
|
|
Q_UNREACHABLE();
|
|
}
|
|
|
|
void KyQuickStyleItem::resolvePalette()
|
|
{
|
|
if (QCoreApplication::testAttribute(Qt::AA_SetPalette))
|
|
return;
|
|
|
|
const QVariant controlPalette = m_control ? m_control->property("palette") : QVariant();
|
|
if (controlPalette.isValid()) {
|
|
m_styleoption->palette = controlPalette.value<QPalette>();
|
|
} else {
|
|
// m_styleoption->palette = m_theme->palette();
|
|
}
|
|
}
|
|
|
|
int KyQuickStyleItem::leftPadding() const
|
|
{
|
|
switch (m_itemType) {
|
|
case Frame: {
|
|
const QRect cr = KyQuickStyleItem::style()->subElementRect(QStyle::SE_ShapedFrameContents, m_styleoption);
|
|
return cr.left() - m_styleoption->rect.left();
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int KyQuickStyleItem::topPadding() const
|
|
{
|
|
switch (m_itemType) {
|
|
case Frame: {
|
|
const QRect cr = KyQuickStyleItem::style()->subElementRect(QStyle::SE_ShapedFrameContents, m_styleoption);
|
|
return cr.top() - m_styleoption->rect.top();
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int KyQuickStyleItem::rightPadding() const
|
|
{
|
|
switch (m_itemType) {
|
|
case Frame: {
|
|
const QRect cr = KyQuickStyleItem::style()->subElementRect(QStyle::SE_ShapedFrameContents, m_styleoption);
|
|
return m_styleoption->rect.right() - cr.right();
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int KyQuickStyleItem::bottomPadding() const
|
|
{
|
|
switch (m_itemType) {
|
|
case Frame: {
|
|
const QRect cr = KyQuickStyleItem::style()->subElementRect(QStyle::SE_ShapedFrameContents, m_styleoption);
|
|
return m_styleoption->rect.bottom() - cr.bottom();
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Property style
|
|
*
|
|
* Returns a simplified style name.
|
|
*
|
|
* QMacStyle = "mac"
|
|
* QWindowsXPStyle = "windowsxp"
|
|
* QFusionStyle = "fusion"
|
|
*/
|
|
|
|
QString KyQuickStyleItem::styleName() const
|
|
{
|
|
QString style = QString::fromLatin1(KyQuickStyleItem::style()->metaObject()->className());
|
|
style = style.toLower();
|
|
if (style.startsWith(QLatin1Char('q')))
|
|
style = style.right(style.length() - 1);
|
|
if (style.endsWith(QLatin1String("style")))
|
|
style = style.left(style.length() - 5);
|
|
return style;
|
|
}
|
|
|
|
QString KyQuickStyleItem::hitTest(int px, int py)
|
|
{
|
|
QStyle::SubControl subcontrol = QStyle::SC_All;
|
|
switch (m_itemType) {
|
|
case SpinBox :{
|
|
subcontrol = KyQuickStyleItem::style()->hitTestComplexControl(QStyle::CC_SpinBox,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
QPoint(px,py), nullptr);
|
|
if (subcontrol == QStyle::SC_SpinBoxUp)
|
|
return QStringLiteral("up");
|
|
else if (subcontrol == QStyle::SC_SpinBoxDown)
|
|
return QStringLiteral("down");
|
|
}
|
|
break;
|
|
|
|
case Slider: {
|
|
subcontrol = KyQuickStyleItem::style()->hitTestComplexControl(QStyle::CC_Slider,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
QPoint(px,py), nullptr);
|
|
if (subcontrol == QStyle::SC_SliderHandle)
|
|
return QStringLiteral("handle");
|
|
}
|
|
break;
|
|
|
|
case ScrollBar: {
|
|
subcontrol = KyQuickStyleItem::style()->hitTestComplexControl(QStyle::CC_ScrollBar,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
QPoint(px,py), nullptr);
|
|
switch (subcontrol) {
|
|
case QStyle::SC_ScrollBarSlider:
|
|
return QStringLiteral("handle");
|
|
|
|
case QStyle::SC_ScrollBarSubLine:
|
|
return QStringLiteral("up");
|
|
|
|
case QStyle::SC_ScrollBarSubPage:
|
|
return QStringLiteral("upPage");
|
|
|
|
case QStyle::SC_ScrollBarAddLine:
|
|
return QStringLiteral("down");
|
|
|
|
case QStyle::SC_ScrollBarAddPage:
|
|
return QStringLiteral("downPage");
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return QStringLiteral("none");
|
|
}
|
|
|
|
QSize KyQuickStyleItem::sizeFromContents(int width, int height)
|
|
{
|
|
initStyleOption();
|
|
|
|
QSize size;
|
|
switch (m_itemType) {
|
|
case RadioButton:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_RadioButton, m_styleoption, QSize(width,height));
|
|
break;
|
|
case CheckBox:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_CheckBox, m_styleoption, QSize(width,height));
|
|
break;
|
|
case ToolBar:
|
|
size = QSize(200, styleName().contains(QLatin1String("windows")) ? 30 : 42);
|
|
break;
|
|
case ToolButton: {
|
|
QStyleOptionToolButton *btn = qstyleoption_cast<QStyleOptionToolButton*>(m_styleoption);
|
|
int w = 0;
|
|
int h = 0;
|
|
if (btn->toolButtonStyle != Qt::ToolButtonTextOnly) {
|
|
QSize icon = btn->iconSize;
|
|
w = icon.width();
|
|
h = icon.height();
|
|
}
|
|
if (btn->toolButtonStyle != Qt::ToolButtonIconOnly) {
|
|
QSize textSize = btn->fontMetrics.size(Qt::TextShowMnemonic, btn->text);
|
|
textSize.setWidth(textSize.width() + btn->fontMetrics.horizontalAdvance(QLatin1Char(' '))*2);
|
|
if (btn->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
|
|
h += 4 + textSize.height();
|
|
if (textSize.width() > w)
|
|
w = textSize.width();
|
|
} else if (btn->toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
|
|
w += 4 + textSize.width();
|
|
if (textSize.height() > h)
|
|
h = textSize.height();
|
|
} else { // TextOnly
|
|
w = textSize.width();
|
|
h = textSize.height();
|
|
}
|
|
}
|
|
btn->rect.setSize(QSize(w, h));
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_ToolButton, m_styleoption, QSize(w, h)); }
|
|
break;
|
|
case Button: {
|
|
QStyleOptionButton *btn = qstyleoption_cast<QStyleOptionButton*>(m_styleoption);
|
|
|
|
int contentWidth = btn->fontMetrics.boundingRect(btn->text).width();
|
|
int contentHeight = btn->fontMetrics.height();
|
|
|
|
if (!btn->icon.isNull()) {
|
|
//+4 matches a hardcoded value in QStyle and acts as a margin between the icon and the text.
|
|
contentWidth += btn->iconSize.width() + 4;
|
|
contentHeight = qMax(btn->fontMetrics.height(), btn->iconSize.height());
|
|
}
|
|
|
|
int newWidth = qMax(width, contentWidth);
|
|
int newHeight = qMax(height, contentHeight);
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_PushButton, m_styleoption, QSize(newWidth, newHeight)); }
|
|
break;
|
|
case ComboBox: {
|
|
QStyleOptionComboBox *btn = qstyleoption_cast<QStyleOptionComboBox*>(m_styleoption);
|
|
int newWidth = qMax(width, btn->fontMetrics.boundingRect(btn->currentText).width());
|
|
int newHeight = qMax(height, btn->fontMetrics.height());
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_ComboBox, m_styleoption, QSize(newWidth, newHeight)); }
|
|
break;
|
|
case Tab: {
|
|
QStyleOptionTab *tab = qstyleoption_cast<QStyleOptionTab*>(m_styleoption);
|
|
|
|
int contentWidth = tab->fontMetrics.boundingRect(tab->text).width();
|
|
int contentHeight = tab->fontMetrics.height();
|
|
|
|
if (!tab->icon.isNull()) {
|
|
//+4 matches a hardcoded value in QStyle and acts as a margin between the icon and the text.
|
|
contentWidth += tab->iconSize.width() + 4;
|
|
contentHeight = qMax(contentHeight, tab->iconSize.height());
|
|
}
|
|
|
|
contentWidth += KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabHSpace, tab);
|
|
contentHeight += KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabVSpace, tab);
|
|
|
|
const int newWidth = qMax(width, contentWidth);
|
|
const int newHeight = qMax(height, contentHeight);
|
|
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_TabBarTab, m_styleoption, QSize(newWidth, newHeight));
|
|
|
|
break;
|
|
}
|
|
case Slider:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_Slider, m_styleoption, QSize(width,height));
|
|
break;
|
|
case ProgressBar:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_ProgressBar, m_styleoption, QSize(width,height));
|
|
break;
|
|
case SpinBox:
|
|
case Edit:
|
|
{
|
|
// We have to create a new style option since we might be calling with a QStyleOptionSpinBox
|
|
QStyleOptionFrame frame;
|
|
//+2 to be consistent with the hardcoded verticalmargin in QLineEdit
|
|
int contentHeight = frame.fontMetrics.height() + 2;
|
|
|
|
frame.state = m_styleoption->state | QStyle::State_Sunken;
|
|
frame.lineWidth = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption, nullptr);
|
|
frame.rect = m_styleoption->rect;
|
|
frame.styleObject = this;
|
|
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_LineEdit,
|
|
&frame, QSize(width, qMax(height, contentHeight)).expandedTo(QApplication::globalStrut()));
|
|
if (m_itemType == SpinBox) {
|
|
size.setWidth(KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_SpinBox,
|
|
m_styleoption, QSize(width + 2, height)).width());
|
|
}
|
|
}
|
|
break;
|
|
case GroupBox: {
|
|
QStyleOptionGroupBox *box = qstyleoption_cast<QStyleOptionGroupBox*>(m_styleoption);
|
|
QFontMetrics metrics(box->fontMetrics);
|
|
int baseWidth = metrics.boundingRect(box->text + QLatin1Char(' ')).width();
|
|
int baseHeight = metrics.height() + m_contentHeight;
|
|
if (box->subControls & QStyle::SC_GroupBoxCheckBox) {
|
|
baseWidth += KyQuickStyleItem::style()->pixelMetric(QStyle::PM_IndicatorWidth);
|
|
baseWidth += KyQuickStyleItem::style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing);
|
|
baseHeight = qMax(baseHeight, KyQuickStyleItem::style()->pixelMetric(QStyle::PM_IndicatorHeight));
|
|
}
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_GroupBox, m_styleoption, QSize(qMax(baseWidth, m_contentWidth), baseHeight));
|
|
}
|
|
break;
|
|
case Header:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_HeaderSection, m_styleoption, QSize(width,height));
|
|
break;
|
|
case ItemRow:
|
|
case Item: //fall through
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_ItemViewItem, m_styleoption, QSize(width,height));
|
|
break;
|
|
case MenuBarItem:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_MenuBarItem, m_styleoption, QSize(width,height));
|
|
break;
|
|
case MenuBar:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_MenuBar, m_styleoption, QSize(width,height));
|
|
break;
|
|
case Menu:
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_Menu, m_styleoption, QSize(width,height));
|
|
break;
|
|
case MenuItem:
|
|
case ComboBoxItem:
|
|
if (static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller) {
|
|
size.setHeight(qMax(QApplication::globalStrut().height(),
|
|
KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuScrollerHeight, nullptr, nullptr)));
|
|
} else {
|
|
size = KyQuickStyleItem::style()->sizeFromContents(QStyle::CT_MenuItem, m_styleoption, QSize(width,height));
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return size.expandedTo(QSize(m_contentWidth, m_contentHeight));
|
|
}
|
|
|
|
qreal KyQuickStyleItem::baselineOffset()
|
|
{
|
|
QRect r;
|
|
bool ceilResult = true; // By default baseline offset rounding is done upwards
|
|
switch (m_itemType) {
|
|
case RadioButton:
|
|
r = KyQuickStyleItem::style()->subElementRect(QStyle::SE_RadioButtonContents, m_styleoption);
|
|
break;
|
|
case Button:
|
|
r = KyQuickStyleItem::style()->subElementRect(QStyle::SE_PushButtonContents, m_styleoption);
|
|
break;
|
|
case CheckBox:
|
|
r = KyQuickStyleItem::style()->subElementRect(QStyle::SE_CheckBoxContents, m_styleoption);
|
|
break;
|
|
case Edit:
|
|
r = KyQuickStyleItem::style()->subElementRect(QStyle::SE_LineEditContents, m_styleoption);
|
|
break;
|
|
case ComboBox:
|
|
if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(m_styleoption)) {
|
|
r = KyQuickStyleItem::style()->subControlRect(QStyle::CC_ComboBox, combo, QStyle::SC_ComboBoxEditField);
|
|
if (styleName() != QLatin1String("mac"))
|
|
r.adjust(0,0,0,1);
|
|
}
|
|
break;
|
|
case SpinBox:
|
|
if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(m_styleoption)) {
|
|
r = KyQuickStyleItem::style()->subControlRect(QStyle::CC_SpinBox, spinbox, QStyle::SC_SpinBoxEditField);
|
|
ceilResult = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (r.height() > 0) {
|
|
const QFontMetrics &fm = m_styleoption->fontMetrics;
|
|
int surplus = r.height() - fm.height();
|
|
if ((surplus & 1) && ceilResult)
|
|
surplus++;
|
|
int result = r.top() + surplus/2 + fm.ascent();
|
|
return result;
|
|
}
|
|
|
|
return 0.;
|
|
}
|
|
|
|
void KyQuickStyleItem::updateBaselineOffset()
|
|
{
|
|
const qreal baseline = baselineOffset();
|
|
if (baseline > 0)
|
|
setBaselineOffset(baseline);
|
|
}
|
|
|
|
void KyQuickStyleItem::setContentWidth(int arg)
|
|
{
|
|
if (m_contentWidth != arg) {
|
|
m_contentWidth = arg;
|
|
emit contentWidthChanged(arg);
|
|
}
|
|
}
|
|
|
|
void KyQuickStyleItem::setContentHeight(int arg)
|
|
{
|
|
if (m_contentHeight != arg) {
|
|
m_contentHeight = arg;
|
|
emit contentHeightChanged(arg);
|
|
}
|
|
}
|
|
|
|
void KyQuickStyleItem::updateSizeHint()
|
|
{
|
|
QSize implicitSize = sizeFromContents(m_contentWidth, m_contentHeight);
|
|
setImplicitSize(implicitSize.width(), implicitSize.height());
|
|
}
|
|
|
|
void KyQuickStyleItem::updateRect()
|
|
{
|
|
initStyleOption();
|
|
m_styleoption->rect.setWidth(width());
|
|
m_styleoption->rect.setHeight(height());
|
|
}
|
|
|
|
int KyQuickStyleItem::pixelMetric(const QString &metric)
|
|
{
|
|
if (metric == QLatin1String("scrollbarExtent"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ScrollBarExtent, nullptr);
|
|
else if (metric == QLatin1String("defaultframewidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_DefaultFrameWidth, m_styleoption);
|
|
else if (metric == QLatin1String("taboverlap"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabOverlap, nullptr);
|
|
else if (metric == QLatin1String("tabbaseoverlap"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, m_styleoption);
|
|
else if (metric == QLatin1String("tabhspace"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabHSpace, nullptr);
|
|
else if (metric == QLatin1String("indicatorwidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_IndicatorWidth, nullptr);
|
|
else if (metric == QLatin1String("exclusiveindicatorwidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ExclusiveIndicatorWidth, nullptr);
|
|
else if (metric == QLatin1String("checkboxlabelspacing"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, nullptr);
|
|
else if (metric == QLatin1String("ratiobuttonlabelspacing"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_RadioButtonLabelSpacing, nullptr);
|
|
else if (metric == QLatin1String("tabvspace"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabVSpace, nullptr);
|
|
else if (metric == QLatin1String("tabbaseheight"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarBaseHeight, nullptr);
|
|
else if (metric == QLatin1String("tabvshift"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, nullptr);
|
|
else if (metric == QLatin1String("menubarhmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuBarHMargin, nullptr);
|
|
else if (metric == QLatin1String("menubarvmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuBarVMargin, nullptr);
|
|
else if (metric == QLatin1String("menubarpanelwidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, nullptr);
|
|
else if (metric == QLatin1String("menubaritemspacing"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuBarItemSpacing, nullptr);
|
|
else if (metric == QLatin1String("spacebelowmenubar"))
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, m_styleoption);
|
|
else if (metric == QLatin1String("menuhmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuHMargin, nullptr);
|
|
else if (metric == QLatin1String("menuvmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuVMargin, nullptr);
|
|
else if (metric == QLatin1String("menupanelwidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuPanelWidth, nullptr);
|
|
else if (metric == QLatin1String("submenuoverlap"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_SubMenuOverlap, nullptr);
|
|
else if (metric == QLatin1String("splitterwidth"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_SplitterWidth, nullptr);
|
|
else if (metric == QLatin1String("scrollbarspacing"))
|
|
return abs(KyQuickStyleItem::style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, nullptr));
|
|
else if (metric == QLatin1String("treeviewindentation"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_TreeViewIndentation, nullptr);
|
|
else if (metric == QLatin1String("layouthorizontalspacing"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr);
|
|
else if (metric == QLatin1String("layoutverticalspacing"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing, nullptr);
|
|
else if (metric == QLatin1String("layoutleftmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr);
|
|
else if (metric == QLatin1String("layouttopmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr);
|
|
else if (metric == QLatin1String("layoutrightmargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr);
|
|
else if (metric == QLatin1String("layoutbottommargin"))
|
|
return KyQuickStyleItem::style()->pixelMetric(QStyle::PM_LayoutBottomMargin, nullptr);
|
|
return 0;
|
|
}
|
|
|
|
QVariant KyQuickStyleItem::styleHint(const QString &metric)
|
|
{
|
|
initStyleOption();
|
|
if (metric == QLatin1String("comboboxpopup")) {
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_ComboBox_Popup, m_styleoption);
|
|
} else if (metric == QLatin1String("highlightedTextColor")) {
|
|
return m_styleoption->palette.highlightedText().color().name();
|
|
} else if (metric == QLatin1String("textColor")) {
|
|
QPalette pal = m_styleoption->palette;
|
|
pal.setCurrentColorGroup(active()? QPalette::Active : QPalette::Inactive);
|
|
return pal.text().color().name();
|
|
} else if (metric == QLatin1String("focuswidget")) {
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_FocusFrame_AboveWidget);
|
|
} else if (metric == QLatin1String("tabbaralignment")) {
|
|
int result = KyQuickStyleItem::style()->styleHint(QStyle::SH_TabBar_Alignment);
|
|
if (result == Qt::AlignCenter)
|
|
return QStringLiteral("center");
|
|
return QStringLiteral("left");
|
|
} else if (metric == QLatin1String("externalScrollBars")) {
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents);
|
|
} else if (metric == QLatin1String("scrollToClickPosition"))
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_ScrollBar_LeftClickAbsolutePosition);
|
|
else if (metric == QLatin1String("activateItemOnSingleClick"))
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
|
|
else if (metric == QLatin1String("submenupopupdelay"))
|
|
return KyQuickStyleItem::style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, m_styleoption);
|
|
else if (metric == QLatin1String("wheelScrollLines"))
|
|
return qApp->wheelScrollLines();
|
|
return 0;
|
|
|
|
// Add SH_Menu_SpaceActivatesItem
|
|
}
|
|
|
|
void KyQuickStyleItem::setHints(const QVariantMap &str)
|
|
{
|
|
if (m_hints != str) {
|
|
m_hints = str;
|
|
initStyleOption();
|
|
updateSizeHint();
|
|
if (m_styleoption->state & QStyle::State_Mini) {
|
|
m_font.setPointSize(9.);
|
|
emit fontChanged();
|
|
} else if (m_styleoption->state & QStyle::State_Small) {
|
|
m_font.setPointSize(11.);
|
|
emit fontChanged();
|
|
} else {
|
|
emit hintChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
void KyQuickStyleItem::resetHints()
|
|
{
|
|
m_hints.clear();
|
|
}
|
|
|
|
|
|
void KyQuickStyleItem::setElementType(const QString &str)
|
|
{
|
|
if (m_type == str)
|
|
return;
|
|
|
|
m_type = str;
|
|
|
|
emit elementTypeChanged();
|
|
if (m_styleoption) {
|
|
delete m_styleoption;
|
|
m_styleoption = nullptr;
|
|
}
|
|
|
|
// Only enable visible if the widget can animate
|
|
if (str == QLatin1String("menu")) {
|
|
m_itemType = Menu;
|
|
} else if (str == QLatin1String("menuitem")) {
|
|
m_itemType = MenuItem;
|
|
} else if (str == QLatin1String("item") || str == QLatin1String("itemrow") || str == QLatin1String("header")) {
|
|
if (str == QLatin1String("header")) {
|
|
m_itemType = Header;
|
|
} else {
|
|
m_itemType = str == QLatin1String("item") ? Item : ItemRow;
|
|
}
|
|
} else if (str == QLatin1String("itembranchindicator")) {
|
|
m_itemType = ItemBranchIndicator;
|
|
} else if (str == QLatin1String("groupbox")) {
|
|
m_itemType = GroupBox;
|
|
} else if (str == QLatin1String("tab")) {
|
|
m_itemType = Tab;
|
|
} else if (str == QLatin1String("tabframe")) {
|
|
m_itemType = TabFrame;
|
|
} else if (str == QLatin1String("comboboxitem")) {
|
|
// Gtk uses qobject cast, hence we need to separate this from menuitem
|
|
// On mac, we temporarily use the menu item because it has more accurate
|
|
// palette.
|
|
m_itemType = ComboBoxItem;
|
|
} else if (str == QLatin1String("toolbar")) {
|
|
m_itemType = ToolBar;
|
|
} else if (str == QLatin1String("toolbutton")) {
|
|
m_itemType = ToolButton;
|
|
} else if (str == QLatin1String("slider")) {
|
|
m_itemType = Slider;
|
|
} else if (str == QLatin1String("frame")) {
|
|
m_itemType = Frame;
|
|
} else if (str == QLatin1String("combobox")) {
|
|
m_itemType = ComboBox;
|
|
} else if (str == QLatin1String("splitter")) {
|
|
m_itemType = Splitter;
|
|
} else if (str == QLatin1String("progressbar")) {
|
|
m_itemType = ProgressBar;
|
|
} else if (str == QLatin1String("button")) {
|
|
m_itemType = Button;
|
|
} else if (str == QLatin1String("checkbox")) {
|
|
m_itemType = CheckBox;
|
|
} else if (str == QLatin1String("radiobutton")) {
|
|
m_itemType = RadioButton;
|
|
} else if (str == QLatin1String("edit")) {
|
|
m_itemType = Edit;
|
|
} else if (str == QLatin1String("spinbox")) {
|
|
m_itemType = SpinBox;
|
|
} else if (str == QLatin1String("scrollbar")) {
|
|
m_itemType = ScrollBar;
|
|
} else if (str == QLatin1String("widget")) {
|
|
m_itemType = Widget;
|
|
} else if (str == QLatin1String("focusframe")) {
|
|
m_itemType = FocusFrame;
|
|
} else if (str == QLatin1String("focusrect")) {
|
|
m_itemType = FocusRect;
|
|
} else if (str == QLatin1String("dial")) {
|
|
m_itemType = Dial;
|
|
} else if (str == QLatin1String("statusbar")) {
|
|
m_itemType = StatusBar;
|
|
} else if (str == QLatin1String("machelpbutton")) {
|
|
m_itemType = MacHelpButton;
|
|
} else if (str == QLatin1String("scrollareacorner")) {
|
|
m_itemType = ScrollAreaCorner;
|
|
} else if (str == QLatin1String("menubar")) {
|
|
m_itemType = MenuBar;
|
|
} else if (str == QLatin1String("menubaritem")) {
|
|
m_itemType = MenuBarItem;
|
|
} else {
|
|
m_itemType = Undefined;
|
|
}
|
|
emit leftPaddingChanged();
|
|
emit rightPaddingChanged();
|
|
emit topPaddingChanged();
|
|
emit bottomPaddingChanged();
|
|
updateSizeHint();
|
|
}
|
|
|
|
QRectF KyQuickStyleItem::subControlRect(const QString &subcontrolString)
|
|
{
|
|
QStyle::SubControl subcontrol = QStyle::SC_None;
|
|
initStyleOption();
|
|
switch (m_itemType) {
|
|
case SpinBox:
|
|
{
|
|
QStyle::ComplexControl control = QStyle::CC_SpinBox;
|
|
if (subcontrolString == QLatin1String("down"))
|
|
subcontrol = QStyle::SC_SpinBoxDown;
|
|
else if (subcontrolString == QLatin1String("up"))
|
|
subcontrol = QStyle::SC_SpinBoxUp;
|
|
else if (subcontrolString == QLatin1String("edit")){
|
|
subcontrol = QStyle::SC_SpinBoxEditField;
|
|
}
|
|
return KyQuickStyleItem::style()->subControlRect(control,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
subcontrol);
|
|
|
|
}
|
|
break;
|
|
case Slider:
|
|
{
|
|
QStyle::ComplexControl control = QStyle::CC_Slider;
|
|
if (subcontrolString == QLatin1String("handle"))
|
|
subcontrol = QStyle::SC_SliderHandle;
|
|
else if (subcontrolString == QLatin1String("groove"))
|
|
subcontrol = QStyle::SC_SliderGroove;
|
|
return KyQuickStyleItem::style()->subControlRect(control,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
subcontrol);
|
|
|
|
}
|
|
break;
|
|
case ScrollBar:
|
|
{
|
|
QStyle::ComplexControl control = QStyle::CC_ScrollBar;
|
|
if (subcontrolString == QLatin1String("slider"))
|
|
subcontrol = QStyle::SC_ScrollBarSlider;
|
|
if (subcontrolString == QLatin1String("groove"))
|
|
subcontrol = QStyle::SC_ScrollBarGroove;
|
|
else if (subcontrolString == QLatin1String("handle"))
|
|
subcontrol = QStyle::SC_ScrollBarSlider;
|
|
else if (subcontrolString == QLatin1String("add"))
|
|
subcontrol = QStyle::SC_ScrollBarAddPage;
|
|
else if (subcontrolString == QLatin1String("sub"))
|
|
subcontrol = QStyle::SC_ScrollBarSubPage;
|
|
return KyQuickStyleItem::style()->subControlRect(control,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
subcontrol);
|
|
}
|
|
break;
|
|
case ItemBranchIndicator: {
|
|
QStyleOption opt;
|
|
opt.rect = QRect(0, 0, implicitWidth(), implicitHeight());
|
|
return KyQuickStyleItem::style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, nullptr);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return QRectF();
|
|
}
|
|
|
|
namespace {
|
|
class QHighDpiPixmapsEnabler1 {
|
|
public:
|
|
QHighDpiPixmapsEnabler1()
|
|
:wasEnabled(false)
|
|
{
|
|
if (!qApp->testAttribute(Qt::AA_UseHighDpiPixmaps)) {
|
|
qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
wasEnabled = true;
|
|
}
|
|
}
|
|
|
|
~QHighDpiPixmapsEnabler1()
|
|
{
|
|
if (wasEnabled)
|
|
qApp->setAttribute(Qt::AA_UseHighDpiPixmaps, false);
|
|
}
|
|
private:
|
|
bool wasEnabled;
|
|
};
|
|
}
|
|
|
|
void KyQuickStyleItem::paint(QPainter *painter)
|
|
{
|
|
initStyleOption();
|
|
if (QStyleOptionMenuItem *opt = qstyleoption_cast<QStyleOptionMenuItem*>(m_styleoption))
|
|
painter->setFont(opt->font);
|
|
else {
|
|
QFont font;
|
|
if (m_styleoption->state & QStyle::State_Mini) {
|
|
font = qApp->font("QMiniFont");
|
|
} else if (m_styleoption->state & QStyle::State_Small) {
|
|
font = qApp->font("QSmallFont");
|
|
}
|
|
painter->setFont(font);
|
|
}
|
|
|
|
// Set AA_UseHighDpiPixmaps when calling style code to make QIcon return
|
|
// "retina" pixmaps. The flag is controlled by the application so we can't
|
|
// set it unconditinally.
|
|
QHighDpiPixmapsEnabler1 enabler;
|
|
|
|
switch (m_itemType) {
|
|
case Button:{
|
|
QWidget wid;
|
|
if(m_buttonType == "MaxButton" || m_buttonType == "MinButton") {
|
|
wid.setProperty("isWindowButton", QVariant(0x01));
|
|
}
|
|
if(m_buttonType == "CloseButton") {
|
|
wid.setProperty("isWindowButton", QVariant(0x02));
|
|
}
|
|
if(m_buttonType == "blueButton") {
|
|
wid.setProperty("isImportant", true);
|
|
}
|
|
if(m_roundButton == "RoundButton") {
|
|
wid.setProperty("isRoundButton", true);
|
|
}
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_PushButton, m_styleoption, painter,&wid);
|
|
}
|
|
break;
|
|
case ItemRow :{
|
|
QPixmap pixmap;
|
|
// Only draw through style once
|
|
const QString pmKey = QLatin1String("itemrow") % QString::number(m_styleoption->state,16) % activeControl();
|
|
if (!QPixmapCache::find(pmKey, &pixmap) || pixmap.width() < width() || height() != pixmap.height()) {
|
|
int newSize = width();
|
|
pixmap = QPixmap(newSize, height());
|
|
pixmap.fill(Qt::transparent);
|
|
QPainter pixpainter(&pixmap);
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelItemViewRow, m_styleoption, &pixpainter);
|
|
if ((styleName() == QLatin1String("mac") || !KyQuickStyleItem::style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected)) && selected()) {
|
|
QPalette pal = QApplication::palette("QAbstractItemView");
|
|
pal.setCurrentColorGroup(m_styleoption->palette.currentColorGroup());
|
|
pixpainter.fillRect(m_styleoption->rect, pal.highlight());
|
|
}
|
|
QPixmapCache::insert(pmKey, pixmap);
|
|
}
|
|
painter->drawPixmap(0, 0, pixmap);
|
|
}
|
|
break;
|
|
case Item:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_ItemViewItem, m_styleoption, painter);
|
|
break;
|
|
case ItemBranchIndicator:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_IndicatorBranch, m_styleoption, painter);
|
|
break;
|
|
case Header:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_Header, m_styleoption, painter);
|
|
break;
|
|
case ToolButton:
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_ToolButton, qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), painter);
|
|
break;
|
|
case Tab:
|
|
{
|
|
if (m_lastFocusReason != Qt::TabFocusReason && m_lastFocusReason != Qt::BacktabFocusReason) {
|
|
m_styleoption->state &= ~QStyle::State_HasFocus;
|
|
}
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_TabBarTab, m_styleoption, painter);
|
|
}
|
|
break;
|
|
case Frame:
|
|
m_styleoption->state |= QStyle::State_Sunken;
|
|
m_styleoption->state &= ~QStyle::State_Raised;
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_ShapedFrame, m_styleoption, painter);
|
|
break;
|
|
case FocusFrame:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_FocusFrame, m_styleoption, painter);
|
|
break;
|
|
case FocusRect:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_FrameFocusRect, m_styleoption, painter);
|
|
break;
|
|
case TabFrame:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_FrameTabWidget, m_styleoption, painter);
|
|
break;
|
|
case MenuBar:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_MenuBarEmptyArea, m_styleoption, painter);
|
|
break;
|
|
case MenuBarItem:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_MenuBarItem, m_styleoption, painter);
|
|
break;
|
|
case MenuItem:
|
|
case ComboBoxItem: { // fall through
|
|
QStyle::ControlElement menuElement =
|
|
static_cast<QStyleOptionMenuItem *>(m_styleoption)->menuItemType == QStyleOptionMenuItem::Scroller ?
|
|
QStyle::CE_MenuScroller : QStyle::CE_MenuItem;
|
|
KyQuickStyleItem::style()->drawControl(menuElement, m_styleoption, painter);
|
|
}
|
|
break;
|
|
case CheckBox:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_CheckBox, m_styleoption, painter);
|
|
break;
|
|
case RadioButton:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_RadioButton, m_styleoption, painter);
|
|
break;
|
|
case Edit:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelLineEdit, m_styleoption, painter);
|
|
break;
|
|
case MacHelpButton:
|
|
//Not managed as mac is not supported
|
|
break;
|
|
case Widget:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_Widget, m_styleoption, painter);
|
|
break;
|
|
case ScrollAreaCorner:
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelScrollAreaCorner, m_styleoption, painter);
|
|
break;
|
|
case Splitter:
|
|
if (m_styleoption->rect.width() == 1)
|
|
painter->fillRect(0, 0, width(), height(), m_styleoption->palette.dark().color());
|
|
else
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_Splitter, m_styleoption, painter);
|
|
break;
|
|
case ComboBox:
|
|
{
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_ComboBox,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
painter);
|
|
// This is needed on mac as it will use the painter color and ignore the palette
|
|
QPen pen = painter->pen();
|
|
painter->setPen(m_styleoption->palette.text().color());
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_ComboBoxLabel, m_styleoption, painter);
|
|
painter->setPen(pen);
|
|
} break;
|
|
case SpinBox:
|
|
#ifdef Q_OS_MAC
|
|
// macstyle depends on the embedded qlineedit to fill the editfield background
|
|
if (styleName() == QLatin1String("mac")) {
|
|
QRect editRect = KyQuickStyleItem::style()->subControlRect(QStyle::CC_SpinBox,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
QStyle::SC_SpinBoxEditField);
|
|
painter->fillRect(editRect.adjusted(-1, -1, 1, 1), m_styleoption->palette.base());
|
|
}
|
|
#endif
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_SpinBox,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
painter);
|
|
break;
|
|
case Slider:
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_Slider,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
painter);
|
|
break;
|
|
case Dial:
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_Dial,
|
|
qstyleoption_cast<QStyleOptionComplex*>(m_styleoption),
|
|
painter);
|
|
break;
|
|
case ProgressBar:
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_ProgressBar, m_styleoption, painter);
|
|
break;
|
|
case ToolBar:
|
|
painter->fillRect(m_styleoption->rect, m_styleoption->palette.window().color());
|
|
KyQuickStyleItem::style()->drawControl(QStyle::CE_ToolBar, m_styleoption, painter);
|
|
painter->save();
|
|
painter->setPen(styleName() != QLatin1String("fusion") ? m_styleoption->palette.dark().color().darker(120) :
|
|
m_styleoption->palette.window().color().lighter(107));
|
|
painter->drawLine(m_styleoption->rect.bottomLeft(), m_styleoption->rect.bottomRight());
|
|
painter->restore();
|
|
break;
|
|
case StatusBar:
|
|
{
|
|
painter->fillRect(m_styleoption->rect, m_styleoption->palette.window().color());
|
|
painter->setPen(m_styleoption->palette.dark().color().darker(120));
|
|
painter->drawLine(m_styleoption->rect.topLeft(), m_styleoption->rect.topRight());
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelStatusBar, m_styleoption, painter);
|
|
}
|
|
break;
|
|
case GroupBox:
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_GroupBox, qstyleoption_cast<QStyleOptionComplex*>(m_styleoption), painter);
|
|
break;
|
|
case ScrollBar:
|
|
KyQuickStyleItem::style()->drawComplexControl(QStyle::CC_ScrollBar, qstyleoption_cast<QStyleOptionSlider *>(m_styleoption), painter);
|
|
break;
|
|
case Menu: {
|
|
QStyleHintReturnMask val;
|
|
KyQuickStyleItem::style()->styleHint(QStyle::SH_Menu_Mask, m_styleoption, nullptr, &val);
|
|
painter->save();
|
|
painter->setClipRegion(val.region);
|
|
painter->fillRect(m_styleoption->rect, m_styleoption->palette.window());
|
|
painter->restore();
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelMenu, m_styleoption, painter);
|
|
|
|
if (int fw = KyQuickStyleItem::style()->pixelMetric(QStyle::PM_MenuPanelWidth)) {
|
|
QStyleOptionFrame frame;
|
|
frame.state = QStyle::State_None;
|
|
frame.lineWidth = fw;
|
|
frame.midLineWidth = 0;
|
|
frame.rect = m_styleoption->rect;
|
|
frame.styleObject = this;
|
|
frame.palette = m_styleoption->palette;
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_FrameMenu, &frame, painter);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
qreal KyQuickStyleItem::textWidth(const QString &text)
|
|
{
|
|
QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics);
|
|
return fm.boundingRect(text).width();
|
|
}
|
|
|
|
qreal KyQuickStyleItem::textHeight(const QString &text)
|
|
{
|
|
QFontMetricsF fm = QFontMetricsF(m_styleoption->fontMetrics);
|
|
return text.isEmpty() ? fm.height() :
|
|
fm.boundingRect(text).height();
|
|
}
|
|
|
|
QString KyQuickStyleItem::elidedText(const QString &text, int elideMode, int width)
|
|
{
|
|
return m_styleoption->fontMetrics.elidedText(text, Qt::TextElideMode(elideMode), width);
|
|
}
|
|
|
|
bool KyQuickStyleItem::hasThemeIcon(const QString &icon) const
|
|
{
|
|
return QIcon::hasThemeIcon(icon);
|
|
}
|
|
|
|
bool KyQuickStyleItem::event(QEvent *ev)
|
|
{
|
|
if (ev->type() == QEvent::StyleAnimationUpdate) {
|
|
if (isVisible()) {
|
|
ev->accept();
|
|
polish();
|
|
}
|
|
return true;
|
|
}
|
|
return QQuickItem::event(ev);
|
|
}
|
|
|
|
void KyQuickStyleItem::setTextureWidth(int w)
|
|
{
|
|
if (m_textureWidth == w)
|
|
return;
|
|
m_textureWidth = w;
|
|
emit textureWidthChanged(m_textureWidth);
|
|
update();
|
|
}
|
|
|
|
void KyQuickStyleItem::setTextureHeight(int h)
|
|
{
|
|
if (m_textureHeight == h)
|
|
return;
|
|
m_textureHeight = h;
|
|
emit textureHeightChanged(m_textureHeight);
|
|
update();
|
|
}
|
|
|
|
QQuickItem *KyQuickStyleItem::control() const
|
|
{
|
|
return m_control;
|
|
}
|
|
|
|
void KyQuickStyleItem::setControl(QQuickItem *control)
|
|
{
|
|
if (control == m_control) {
|
|
return;
|
|
}
|
|
|
|
if (m_control) {
|
|
m_control->removeEventFilter(this);
|
|
disconnect(m_control, nullptr, this, nullptr);
|
|
}
|
|
|
|
m_control = control;
|
|
|
|
if (m_control) {
|
|
m_control->installEventFilter(this);
|
|
|
|
if (m_control->window()) {
|
|
m_window = m_control->window();
|
|
m_window->installEventFilter(this);
|
|
}
|
|
connect(m_control, &QQuickItem::windowChanged, this,
|
|
[this](QQuickWindow *window) {
|
|
if (m_window) {
|
|
m_window->removeEventFilter(this);
|
|
}
|
|
m_window = window;
|
|
if (m_window) {
|
|
m_window->installEventFilter(this);
|
|
}
|
|
});
|
|
}
|
|
|
|
emit controlChanged();
|
|
}
|
|
|
|
QSGNode *KyQuickStyleItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
|
|
{
|
|
if (m_image.isNull()) {
|
|
delete node;
|
|
return nullptr;
|
|
}
|
|
|
|
QSGNinePatchNode *styleNode = static_cast<QSGNinePatchNode *>(node);
|
|
if (!styleNode)
|
|
styleNode = window()->createNinePatchNode();
|
|
|
|
#ifdef QSG_RUNTIME_DESCRIPTION
|
|
qsgnode_set_description(styleNode,
|
|
QString::fromLatin1("%1:%2, '%3'")
|
|
.arg(styleName())
|
|
.arg(elementType())
|
|
.arg(text()));
|
|
#endif
|
|
|
|
styleNode->setTexture(window()->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas));
|
|
styleNode->setBounds(boundingRect());
|
|
styleNode->setDevicePixelRatio(window()->devicePixelRatio());
|
|
styleNode->setPadding(m_border.left(), m_border.top(), m_border.right(), m_border.bottom());
|
|
styleNode->update();
|
|
|
|
return styleNode;
|
|
}
|
|
|
|
void KyQuickStyleItem::updatePolish()
|
|
{
|
|
if (width() >= 1 && height() >= 1) { // Note these are reals so 1 pixel is minimum
|
|
float devicePixelRatio = window() ? window()->devicePixelRatio() : qApp->devicePixelRatio();
|
|
int w = m_textureWidth > 0 ? m_textureWidth : width();
|
|
int h = m_textureHeight > 0 ? m_textureHeight : height();
|
|
m_image = QImage(w * devicePixelRatio, h * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
|
|
m_image.setDevicePixelRatio(devicePixelRatio);
|
|
m_image.fill(Qt::transparent);
|
|
QPainter painter(&m_image);
|
|
painter.setLayoutDirection(qApp->layoutDirection());
|
|
paint(&painter);
|
|
QQuickItem::update();
|
|
} else if (!m_image.isNull()) {
|
|
m_image = QImage();
|
|
QQuickItem::update();
|
|
}
|
|
}
|
|
|
|
bool KyQuickStyleItem::eventFilter(QObject *watched, QEvent *event)
|
|
{
|
|
if (watched == m_control) {
|
|
if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
|
|
QFocusEvent *fe = static_cast<QFocusEvent *>(event);
|
|
m_lastFocusReason = fe->reason();
|
|
}
|
|
} else if (watched == m_window.data()) {
|
|
if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
|
|
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
|
|
if (ke->key() == Qt::Key_Alt) {
|
|
updateItem();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return QQuickItem::eventFilter(watched, event);
|
|
}
|
|
|
|
void KyQuickStyleItem::styleChanged()
|
|
{
|
|
if (!qApp->style() || QApplication::closingDown()) {
|
|
return;
|
|
}
|
|
|
|
Q_ASSERT(qApp->style() != sender());
|
|
|
|
connect(qApp->style(), &QObject::destroyed, this, &KyQuickStyleItem::styleChanged);
|
|
|
|
updateSizeHint();
|
|
updateItem();
|
|
}
|
|
|
|
QPixmap QQuickTableRowImageProvider1::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
|
|
{
|
|
Q_UNUSED (requestedSize);
|
|
int width = 16;
|
|
int height = 16;
|
|
if (size)
|
|
*size = QSize(width, height);
|
|
|
|
QPixmap pixmap(width, height);
|
|
|
|
QStyleOptionViewItem opt;
|
|
opt.state |= QStyle::State_Enabled;
|
|
opt.rect = QRect(0, 0, width, height);
|
|
QString style = QString::fromLatin1(KyQuickStyleItem::style()->metaObject()->className());
|
|
opt.features = {};
|
|
|
|
if (id.contains(QLatin1String("selected")))
|
|
opt.state |= QStyle::State_Selected;
|
|
|
|
if (id.contains(QLatin1String("active"))) {
|
|
opt.state |= QStyle::State_Active;
|
|
opt.palette.setCurrentColorGroup(QPalette::Active);
|
|
} else
|
|
opt.palette.setCurrentColorGroup(QPalette::Inactive);
|
|
|
|
if (id.contains(QLatin1String("alternate")))
|
|
opt.features |= QStyleOptionViewItem::Alternate;
|
|
|
|
QPalette pal = QApplication::palette("QAbstractItemView");
|
|
if (opt.state & QStyle::State_Selected && (style.contains(QLatin1String("Mac")) ||
|
|
!KyQuickStyleItem::style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected))) {
|
|
pal.setCurrentColorGroup(opt.palette.currentColorGroup());
|
|
pixmap.fill(pal.highlight().color());
|
|
} else {
|
|
pixmap.fill(pal.base().color());
|
|
QPainter pixpainter(&pixmap);
|
|
KyQuickStyleItem::style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, &pixpainter);
|
|
}
|
|
return pixmap;
|
|
}
|