qt5-ukui-platformtheme/ukui-styles/qt5-style-ukui/qt5-ukui-style-helper.cpp

204 lines
6.6 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: Yue Lan <lanyue@kylinos.cn>
*
*/
#include "qt5-ukui-style-helper.h"
#include <QPainter>
#include <QStyleOption>
#include <QWidget>
#include <QPainterPath>
static inline qreal mixQreal(qreal a, qreal b, qreal bias)
{
return a + (b - a) * bias;
}
const QRegion getRoundedRectRegion(const QRect &rect, qreal radius_x, qreal radius_y)
{
QPainterPath path;
path.addRoundedRect(rect, radius_x, radius_y);
return path.toFillPolygon().toPolygon();
}
qreal calcRadial(const QStyleOptionSlider *dial, int position)
{
int currentSliderPosition = position;
if (!dial->upsideDown) {
if (position == dial->minimum)
currentSliderPosition = dial->maximum;
else if (position == dial->maximum)
currentSliderPosition = dial->minimum;
else
currentSliderPosition = dial->maximum - position;
}
qreal a = 0;
if (dial->maximum == dial->minimum)
a = M_PI / 2;
else if (dial->dialWrapping)
a = M_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * M_PI / (dial->maximum - dial->minimum);
else
a = (M_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * M_PI / (dial->maximum - dial->minimum)) / 6;
return a;
}
QPolygonF calcLines(const QStyleOptionSlider *dial, int offset)
{
QPolygonF poly(0);
int width = dial->rect.width();
int height = dial->rect.height();
qreal r = qMin(width, height) / 2;
qreal xc = width / 2;
qreal yc = height / 2;
const int ns = dial->tickInterval;
if (!ns) // Invalid values may be set by Qt Designer.
return poly;
int notches = (dial->maximum + ns - 1 - dial->minimum) / ns;
if (notches <= 0)
return poly;
if (dial->maximum < dial->minimum || dial->maximum - dial->minimum > 1000) {
int maximum = dial->minimum + 1000;
notches = (maximum + ns - 1 - dial->minimum) / ns;
}
poly.resize(2 + 2 * notches);
int smallLineSize = offset / 2;
for (int i = 0; i <= notches; ++i) {
qreal angle = dial->dialWrapping ? M_PI * 3 / 2 - i * 2 * M_PI / notches
: (M_PI * 8 - i * 10 * M_PI / notches) / 6;
qreal s = qSin(angle);
qreal c = qCos(angle);
poly[2 * i] = QPointF(xc + (r + 0.5 - smallLineSize) * c,
yc - (r + 0.5 - smallLineSize) * s);
poly[2 * i + 1] = QPointF(xc + r * c, yc - r * s);
}
return poly;
}
void tabLayout(const QStyleOptionTab *tab, const QWidget *widget, const QStyle *style, QRect *textRect, QRect *iconRect)
{
Q_ASSERT(textRect);
Q_ASSERT(iconRect);
QRect rect = tab->rect;
bool verticalTabs = tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::RoundedWest
|| tab->shape == QTabBar::TriangularEast || tab->shape == QTabBar::TriangularWest;
int iconExtent = style->pixelMetric(QStyle::PM_SmallIconSize);
if (verticalTabs)
rect.setRect(0, 0, rect.height(), rect.width());
int hpadding = style->pixelMetric(QStyle::PM_TabBarTabHSpace, tab, widget) / 2;
int vpadding = style->pixelMetric(QStyle::PM_TabBarTabVSpace, tab, widget) / 2;
rect.adjust(hpadding, vpadding, -hpadding, -vpadding);
// left widget
if (!tab->leftButtonSize.isEmpty()) {
rect.setLeft(rect.left() + 8 + (verticalTabs ? tab->leftButtonSize.height() : tab->leftButtonSize.width()));
}
// right widget
if (!tab->rightButtonSize.isEmpty()) {
rect.setRight(rect.right() - 8 - (verticalTabs ? tab->rightButtonSize.height() : tab->rightButtonSize.width()));
}
// icon
if (!tab->icon.isNull()) {
QSize iconSize = tab->iconSize;
if (!iconSize.isValid()) {
iconSize = QSize(iconExtent, iconExtent);
}
QSize tabIconSize = tab->icon.actualSize(iconSize,
(tab->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
(tab->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
// High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
*iconRect = QRect(rect.left(), rect.center().y() - tabIconSize.height() / 2,
tabIconSize.width(), tabIconSize.height());
if (!verticalTabs)
*iconRect = style->visualRect(tab->direction, tab->rect, *iconRect);
rect.setLeft(rect.left() + tabIconSize.width() + 8);
}
if (!verticalTabs)
rect = style->visualRect(tab->direction, tab->rect, rect);
*textRect = rect;
}
QColor mixColor(const QColor &c1, const QColor &c2, qreal bias)
{
if (bias <= 0.0) {
return c1;
}
if (bias >= 1.0) {
return c2;
}
if (qIsNaN(bias)) {
return c1;
}
qreal r = mixQreal(c1.redF(), c2.redF(), bias);
qreal g = mixQreal(c1.greenF(), c2.greenF(), bias);
qreal b = mixQreal(c1.blueF(), c2.blueF(), bias);
qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias);
return QColor::fromRgbF(r, g, b, a);
}
void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
const QRect &rect, QPainter *painter, const QWidget *widget)
{
QStyle::PrimitiveElement pe;
switch (toolbutton->arrowType) {
case Qt::LeftArrow:
pe = QStyle::PE_IndicatorArrowLeft;
break;
case Qt::RightArrow:
pe = QStyle::PE_IndicatorArrowRight;
break;
case Qt::UpArrow:
pe = QStyle::PE_IndicatorArrowUp;
break;
case Qt::DownArrow:
pe = QStyle::PE_IndicatorArrowDown;
break;
default:
return;
}
QStyleOption arrowOpt = *toolbutton;
arrowOpt.rect = rect;
style->drawPrimitive(pe, &arrowOpt, painter, widget);
}