mirror of
https://gitgud.io/wackyideas/aerothemeplasma-kde6.git
synced 2024-08-15 00:43:45 +00:00
1791 lines
61 KiB
C++
1791 lines
61 KiB
C++
|
/*
|
||
|
* SPDX-FileCopyrightText: 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||
|
*/
|
||
|
|
||
|
#include "breezehelper.h"
|
||
|
|
||
|
#include "breeze.h"
|
||
|
#include "breezepropertynames.h"
|
||
|
|
||
|
#include <KColorScheme>
|
||
|
#include <KColorUtils>
|
||
|
#include <KIconLoader>
|
||
|
#include <KWindowSystem>
|
||
|
#include <qobject.h>
|
||
|
#if __has_include(<KX11Extras>)
|
||
|
#include <KX11Extras>
|
||
|
#endif
|
||
|
|
||
|
#include <QApplication>
|
||
|
#include <QDBusConnection>
|
||
|
#include <QDockWidget>
|
||
|
#include <QFileInfo>
|
||
|
#include <QMainWindow>
|
||
|
#include <QMdiArea>
|
||
|
#include <QMenuBar>
|
||
|
#include <QPainter>
|
||
|
#include <QStyleOption>
|
||
|
#include <QWindow>
|
||
|
|
||
|
#include <QDialog>
|
||
|
#include <algorithm>
|
||
|
|
||
|
namespace Breeze
|
||
|
{
|
||
|
//* contrast for arrow and treeline rendering
|
||
|
static const qreal arrowShade = 0.15;
|
||
|
|
||
|
static const qreal highlightBackgroundAlpha = 0.33;
|
||
|
|
||
|
static const auto radioCheckSunkenDarkeningFactor = 110;
|
||
|
|
||
|
PaletteChangedEventFilter::PaletteChangedEventFilter(Helper *helper)
|
||
|
: QObject(helper)
|
||
|
, _helper(helper)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool PaletteChangedEventFilter::eventFilter(QObject *watched, QEvent *event)
|
||
|
{
|
||
|
if (event->type() != QEvent::ApplicationPaletteChange || watched != qApp) {
|
||
|
return QObject::eventFilter(watched, event);
|
||
|
}
|
||
|
if (!qApp->property("KDE_COLOR_SCHEME_PATH").isValid()) {
|
||
|
return QObject::eventFilter(watched, event);
|
||
|
}
|
||
|
const auto path = qApp->property("KDE_COLOR_SCHEME_PATH").toString();
|
||
|
if (!path.isEmpty()) {
|
||
|
KConfig config(path, KConfig::SimpleConfig);
|
||
|
KConfigGroup group(config.group(QStringLiteral("WM")));
|
||
|
const QPalette palette(QApplication::palette());
|
||
|
_helper->_activeTitleBarColor = group.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight));
|
||
|
_helper->_activeTitleBarTextColor = group.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText));
|
||
|
_helper->_inactiveTitleBarColor = group.readEntry("inactiveBackground", palette.color(QPalette::Disabled, QPalette::Highlight));
|
||
|
_helper->_inactiveTitleBarTextColor = group.readEntry("inactiveForeground", palette.color(QPalette::Disabled, QPalette::HighlightedText));
|
||
|
}
|
||
|
return QObject::eventFilter(watched, event);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
Helper::Helper(KSharedConfig::Ptr config, QObject *parent)
|
||
|
: QObject(parent)
|
||
|
, _config(std::move(config))
|
||
|
, _kwinConfig(KSharedConfig::openConfig("kwinrc"))
|
||
|
, _decorationConfig(new InternalSettings())
|
||
|
, _eventFilter(new PaletteChangedEventFilter(this))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
KSharedConfig::Ptr Helper::config() const
|
||
|
{
|
||
|
return _config;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QSharedPointer<InternalSettings> Helper::decorationConfig() const
|
||
|
{
|
||
|
return _decorationConfig;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
void Helper::loadConfig()
|
||
|
{
|
||
|
_viewFocusBrush = KStatefulBrush(KColorScheme::View, KColorScheme::FocusColor);
|
||
|
_viewHoverBrush = KStatefulBrush(KColorScheme::View, KColorScheme::HoverColor);
|
||
|
_buttonFocusBrush = KStatefulBrush(KColorScheme::Button, KColorScheme::FocusColor);
|
||
|
_buttonHoverBrush = KStatefulBrush(KColorScheme::Button, KColorScheme::HoverColor);
|
||
|
_viewNegativeTextBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NegativeText);
|
||
|
_viewNeutralTextBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NeutralText);
|
||
|
|
||
|
const QPalette palette(QApplication::palette());
|
||
|
_config->reparseConfiguration();
|
||
|
_kwinConfig->reparseConfiguration();
|
||
|
_cachedAutoValid = false;
|
||
|
_decorationConfig->load();
|
||
|
|
||
|
KConfigGroup globalGroup(_config->group(QStringLiteral("WM")));
|
||
|
_activeTitleBarColor = globalGroup.readEntry("activeBackground", palette.color(QPalette::Active, QPalette::Highlight));
|
||
|
_activeTitleBarTextColor = globalGroup.readEntry("activeForeground", palette.color(QPalette::Active, QPalette::HighlightedText));
|
||
|
_inactiveTitleBarColor = globalGroup.readEntry("inactiveBackground", palette.color(QPalette::Disabled, QPalette::Highlight));
|
||
|
_inactiveTitleBarTextColor = globalGroup.readEntry("inactiveForeground", palette.color(QPalette::Disabled, QPalette::HighlightedText));
|
||
|
|
||
|
if (const QString colorSchemePath = qApp->property("KDE_COLOR_SCHEME_PATH").toString(); !colorSchemePath.isEmpty()) {
|
||
|
KConfig config(colorSchemePath, KConfig::SimpleConfig);
|
||
|
KConfigGroup appGroup(config.group(QStringLiteral("WM")));
|
||
|
_activeTitleBarColor = appGroup.readEntry("activeBackground", _activeTitleBarColor);
|
||
|
_activeTitleBarTextColor = appGroup.readEntry("activeForeground", _activeTitleBarTextColor);
|
||
|
_inactiveTitleBarColor = appGroup.readEntry("inactiveBackground", _inactiveTitleBarColor);
|
||
|
_inactiveTitleBarTextColor = appGroup.readEntry("inactiveForeground", _inactiveTitleBarTextColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Helper::installEventFilter(QApplication *app) const
|
||
|
{
|
||
|
if (app) {
|
||
|
app->installEventFilter(_eventFilter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Helper::removeEventFilter(QApplication *app) const
|
||
|
{
|
||
|
if (app) {
|
||
|
app->removeEventFilter(_eventFilter);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QColor transparentize(const QColor &color, qreal amount)
|
||
|
{
|
||
|
auto clone = color;
|
||
|
clone.setAlphaF(amount);
|
||
|
return clone;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::frameOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor outline(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), Metrics::Bias_Default));
|
||
|
|
||
|
// focus takes precedence over hover
|
||
|
if (mode == AnimationFocus) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
|
||
|
if (mouseOver) {
|
||
|
outline = KColorUtils::mix(hover, focus, opacity);
|
||
|
} else {
|
||
|
outline = KColorUtils::mix(outline, focus, opacity);
|
||
|
}
|
||
|
|
||
|
} else if (hasFocus) {
|
||
|
outline = focusColor(palette);
|
||
|
|
||
|
} else if (mode == AnimationHover) {
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
outline = KColorUtils::mix(outline, hover, opacity);
|
||
|
|
||
|
} else if (mouseOver) {
|
||
|
outline = hoverColor(palette);
|
||
|
}
|
||
|
|
||
|
return outline;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::focusOutlineColor(const QPalette &palette) const
|
||
|
{
|
||
|
return KColorUtils::mix(focusColor(palette), palette.color(QPalette::WindowText), 0.15);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::hoverOutlineColor(const QPalette &palette) const
|
||
|
{
|
||
|
return KColorUtils::mix(hoverColor(palette), palette.color(QPalette::WindowText), 0.15);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::buttonFocusOutlineColor(const QPalette &palette) const
|
||
|
{
|
||
|
return KColorUtils::mix(buttonFocusColor(palette), palette.color(QPalette::ButtonText), 0.15);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::buttonHoverOutlineColor(const QPalette &palette) const
|
||
|
{
|
||
|
return KColorUtils::mix(buttonHoverColor(palette), palette.color(QPalette::ButtonText), 0.15);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::sidePanelOutlineColor(const QPalette &palette, bool hasFocus, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor outline(palette.color(QPalette::Inactive, QPalette::Highlight));
|
||
|
const QColor &focus = palette.color(QPalette::Active, QPalette::Highlight);
|
||
|
|
||
|
if (mode == AnimationFocus) {
|
||
|
outline = KColorUtils::mix(outline, focus, opacity);
|
||
|
|
||
|
} else if (hasFocus) {
|
||
|
outline = focus;
|
||
|
}
|
||
|
|
||
|
return outline;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::frameBackgroundColor(const QPalette &palette, QPalette::ColorGroup group) const
|
||
|
{
|
||
|
return KColorUtils::mix(palette.color(group, QPalette::Window), palette.color(group, QPalette::Base), 0.3);
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::arrowColor(const QPalette &palette, QPalette::ColorGroup group, QPalette::ColorRole role) const
|
||
|
{
|
||
|
switch (role) {
|
||
|
case QPalette::Text:
|
||
|
return KColorUtils::mix(palette.color(group, QPalette::Text), palette.color(group, QPalette::Base), arrowShade);
|
||
|
case QPalette::WindowText:
|
||
|
return KColorUtils::mix(palette.color(group, QPalette::WindowText), palette.color(group, QPalette::Window), arrowShade);
|
||
|
case QPalette::ButtonText:
|
||
|
return KColorUtils::mix(palette.color(group, QPalette::ButtonText), palette.color(group, QPalette::Button), arrowShade);
|
||
|
default:
|
||
|
return palette.color(group, role);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::arrowColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor outline(arrowColor(palette, QPalette::WindowText));
|
||
|
if (mode == AnimationHover) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
if (hasFocus) {
|
||
|
outline = KColorUtils::mix(focus, hover, opacity);
|
||
|
} else {
|
||
|
outline = KColorUtils::mix(outline, hover, opacity);
|
||
|
}
|
||
|
|
||
|
} else if (mouseOver) {
|
||
|
outline = hoverColor(palette);
|
||
|
|
||
|
} else if (mode == AnimationFocus) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
outline = KColorUtils::mix(outline, focus, opacity);
|
||
|
|
||
|
} else if (hasFocus) {
|
||
|
outline = focusColor(palette);
|
||
|
}
|
||
|
|
||
|
return outline;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::sliderOutlineColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor outline(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.4));
|
||
|
|
||
|
// hover takes precedence over focus
|
||
|
if (mode == AnimationHover) {
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
const QColor focus(focusColor(palette));
|
||
|
if (hasFocus) {
|
||
|
outline = KColorUtils::mix(focus, hover, opacity);
|
||
|
} else {
|
||
|
outline = KColorUtils::mix(outline, hover, opacity);
|
||
|
}
|
||
|
|
||
|
} else if (mouseOver) {
|
||
|
outline = hoverColor(palette);
|
||
|
|
||
|
} else if (mode == AnimationFocus) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
outline = KColorUtils::mix(outline, focus, opacity);
|
||
|
|
||
|
} else if (hasFocus) {
|
||
|
outline = focusColor(palette);
|
||
|
}
|
||
|
|
||
|
return outline;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::scrollBarHandleColor(const QPalette &palette, bool mouseOver, bool hasFocus, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor color(alphaColor(palette.color(QPalette::WindowText), 0.5));
|
||
|
|
||
|
// hover takes precedence over focus
|
||
|
if (mode == AnimationHover) {
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
const QColor focus(focusColor(palette));
|
||
|
if (hasFocus) {
|
||
|
color = KColorUtils::mix(focus, hover, opacity);
|
||
|
} else {
|
||
|
color = KColorUtils::mix(color, hover, opacity);
|
||
|
}
|
||
|
|
||
|
} else if (mouseOver) {
|
||
|
color = hoverColor(palette);
|
||
|
|
||
|
} else if (mode == AnimationFocus) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
color = KColorUtils::mix(color, focus, opacity);
|
||
|
|
||
|
} else if (hasFocus) {
|
||
|
color = focusColor(palette);
|
||
|
}
|
||
|
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QColor Helper::checkBoxIndicatorColor(const QPalette &palette, bool mouseOver, bool active, qreal opacity, AnimationMode mode) const
|
||
|
{
|
||
|
QColor color(KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), 0.6));
|
||
|
if (mode == AnimationHover) {
|
||
|
const QColor focus(focusColor(palette));
|
||
|
const QColor hover(hoverColor(palette));
|
||
|
if (active) {
|
||
|
color = KColorUtils::mix(focus, hover, opacity);
|
||
|
} else {
|
||
|
color = KColorUtils::mix(color, hover, opacity);
|
||
|
}
|
||
|
|
||
|
} else if (mouseOver) {
|
||
|
color = hoverColor(palette);
|
||
|
|
||
|
} else if (active) {
|
||
|
color = focusColor(palette);
|
||
|
}
|
||
|
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QColor Helper::separatorColor(const QPalette &palette) const
|
||
|
{
|
||
|
return KColorUtils::mix(palette.color(QPalette::Window), palette.color(QPalette::WindowText), Metrics::Bias_Default);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QPalette Helper::disabledPalette(const QPalette &source, qreal ratio) const
|
||
|
{
|
||
|
QPalette copy(source);
|
||
|
|
||
|
const QList<QPalette::ColorRole> roles =
|
||
|
{QPalette::Window, QPalette::Highlight, QPalette::WindowText, QPalette::ButtonText, QPalette::Text, QPalette::Button};
|
||
|
for (const QPalette::ColorRole &role : roles) {
|
||
|
copy.setColor(role, KColorUtils::mix(source.color(QPalette::Active, role), source.color(QPalette::Disabled, role), 1.0 - ratio));
|
||
|
}
|
||
|
|
||
|
return copy;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
QColor Helper::alphaColor(QColor color, qreal alpha) const
|
||
|
{
|
||
|
if (alpha >= 0 && alpha < 1.0) {
|
||
|
color.setAlphaF(alpha * color.alphaF());
|
||
|
}
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderDebugFrame(QPainter *painter, const QRect &rect) const
|
||
|
{
|
||
|
painter->save();
|
||
|
painter->setRenderHints(QPainter::Antialiasing);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->setPen(Qt::red);
|
||
|
painter->drawRect(strokedRect(rect));
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderFocusRect(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Sides sides) const
|
||
|
{
|
||
|
if (!color.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
painter->save();
|
||
|
painter->setRenderHints(QPainter::Antialiasing);
|
||
|
painter->setBrush(color);
|
||
|
|
||
|
if (!(outline.isValid() && sides)) {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->drawRect(rect);
|
||
|
|
||
|
} else {
|
||
|
painter->setClipRect(rect);
|
||
|
|
||
|
QRectF copy(strokedRect(rect));
|
||
|
|
||
|
const qreal radius(frameRadius(PenWidth::Frame));
|
||
|
if (!(sides & SideTop)) {
|
||
|
copy.adjust(0, -radius, 0, 0);
|
||
|
}
|
||
|
if (!(sides & SideBottom)) {
|
||
|
copy.adjust(0, 0, 0, radius);
|
||
|
}
|
||
|
if (!(sides & SideLeft)) {
|
||
|
copy.adjust(-radius, 0, 0, 0);
|
||
|
}
|
||
|
if (!(sides & SideRight)) {
|
||
|
copy.adjust(0, 0, radius, 0);
|
||
|
}
|
||
|
|
||
|
painter->setPen(outline);
|
||
|
// painter->setBrush( Qt::NoBrush );
|
||
|
painter->drawRoundedRect(copy, radius, radius);
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderFocusLine(QPainter *painter, const QRect &rect, const QColor &color) const
|
||
|
{
|
||
|
if (!color.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
painter->save();
|
||
|
painter->setRenderHint(QPainter::Antialiasing, false);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->setPen(color);
|
||
|
|
||
|
painter->translate(0, 2);
|
||
|
painter->drawLine(rect.bottomLeft(), rect.bottomRight());
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderFrameWithSides(QPainter *painter, const QRect &rect, const QColor &color, Qt::Edges edges, const QColor &outline) const
|
||
|
{
|
||
|
painter->save();
|
||
|
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
|
||
|
QRectF frameRect(rect);
|
||
|
|
||
|
// set brush
|
||
|
painter->setBrush(color);
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
|
||
|
// render
|
||
|
painter->drawRect(frameRect);
|
||
|
|
||
|
// set brush again
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->setPen(outline);
|
||
|
|
||
|
// manually apply the effects of StrokedRect here but only to the edges with a frame
|
||
|
if (edges & Qt::LeftEdge) {
|
||
|
frameRect.adjust(0.5, 0.0, 0.0, 0.0);
|
||
|
}
|
||
|
if (edges & Qt::RightEdge) {
|
||
|
frameRect.adjust(0.0, 0, -0.5, 0.0);
|
||
|
}
|
||
|
if (edges & Qt::TopEdge) {
|
||
|
frameRect.adjust(0.0, 0.5, 0.0, 0.0);
|
||
|
}
|
||
|
if (edges & Qt::BottomEdge) {
|
||
|
frameRect.adjust(0.0, 0.0, 0.0, -0.5);
|
||
|
}
|
||
|
|
||
|
// draw lines
|
||
|
if (edges & Qt::LeftEdge) {
|
||
|
painter->drawLine(QLineF(frameRect.topLeft(), frameRect.bottomLeft()));
|
||
|
}
|
||
|
if (edges & Qt::RightEdge) {
|
||
|
painter->drawLine(QLineF(frameRect.topRight(), frameRect.bottomRight()));
|
||
|
}
|
||
|
if (edges & Qt::TopEdge) {
|
||
|
painter->drawLine(QLineF(frameRect.topLeft(), frameRect.topRight()));
|
||
|
}
|
||
|
if (edges & Qt::BottomEdge) {
|
||
|
painter->drawLine(QLineF(frameRect.bottomLeft(), frameRect.bottomRight()));
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline) const
|
||
|
{
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
|
||
|
QRectF frameRect(rect);
|
||
|
qreal radius(frameRadius(PenWidth::NoPen));
|
||
|
|
||
|
// set pen
|
||
|
if (outline.isValid()) {
|
||
|
painter->setPen(outline);
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
|
||
|
|
||
|
} else {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
}
|
||
|
|
||
|
// set brush
|
||
|
if (color.isValid()) {
|
||
|
painter->setBrush(color);
|
||
|
} else {
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
}
|
||
|
|
||
|
// render
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderSidePanelFrame(QPainter *painter, const QRect &rect, const QColor &outline, Side side) const
|
||
|
{
|
||
|
// check color
|
||
|
if (!outline.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// adjust rect
|
||
|
QRectF frameRect(strokedRect(rect));
|
||
|
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
painter->setPen(outline);
|
||
|
|
||
|
// render
|
||
|
switch (side) {
|
||
|
default:
|
||
|
case SideLeft:
|
||
|
painter->drawLine(frameRect.topRight(), frameRect.bottomRight());
|
||
|
break;
|
||
|
|
||
|
case SideTop:
|
||
|
painter->drawLine(frameRect.topLeft(), frameRect.topRight());
|
||
|
break;
|
||
|
|
||
|
case SideRight:
|
||
|
painter->drawLine(frameRect.topLeft(), frameRect.bottomLeft());
|
||
|
break;
|
||
|
|
||
|
case SideBottom:
|
||
|
painter->drawLine(frameRect.bottomLeft(), frameRect.bottomRight());
|
||
|
break;
|
||
|
|
||
|
case AllSides: {
|
||
|
const qreal radius(frameRadius(PenWidth::Frame));
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderMenuFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool roundCorners, Qt::Edges seamlessEdges) const
|
||
|
{
|
||
|
painter->save();
|
||
|
|
||
|
// set brush
|
||
|
if (color.isValid()) {
|
||
|
painter->setBrush(color);
|
||
|
} else {
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
}
|
||
|
|
||
|
// We simulate being able to independently adjust corner radii by
|
||
|
// setting a clip region and then extending the rectangle beyond it.
|
||
|
if (seamlessEdges != Qt::Edges()) {
|
||
|
painter->setClipRect(rect);
|
||
|
}
|
||
|
|
||
|
if (roundCorners) {
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
QRectF frameRect(rect);
|
||
|
qreal radius(frameRadius(PenWidth::NoPen));
|
||
|
|
||
|
frameRect.adjust( //
|
||
|
seamlessEdges.testFlag(Qt::LeftEdge) ? -radius : 0,
|
||
|
seamlessEdges.testFlag(Qt::TopEdge) ? -radius : 0,
|
||
|
seamlessEdges.testFlag(Qt::RightEdge) ? radius : 0,
|
||
|
seamlessEdges.testFlag(Qt::BottomEdge) ? radius : 0);
|
||
|
|
||
|
// set pen
|
||
|
if (outline.isValid()) {
|
||
|
painter->setPen(outline);
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
|
||
|
|
||
|
} else {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
}
|
||
|
|
||
|
// render
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
|
||
|
} else {
|
||
|
painter->setRenderHint(QPainter::Antialiasing, false);
|
||
|
QRect frameRect(rect);
|
||
|
|
||
|
frameRect.adjust( //
|
||
|
seamlessEdges.testFlag(Qt::LeftEdge) ? 1 : 0,
|
||
|
seamlessEdges.testFlag(Qt::TopEdge) ? 1 : 0,
|
||
|
seamlessEdges.testFlag(Qt::RightEdge) ? -1 : 0,
|
||
|
seamlessEdges.testFlag(Qt::BottomEdge) ? -1 : 0);
|
||
|
|
||
|
if (outline.isValid()) {
|
||
|
painter->setPen(outline);
|
||
|
frameRect.adjust(0, 0, -1, -1);
|
||
|
|
||
|
} else {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
}
|
||
|
|
||
|
painter->drawRect(frameRect);
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderButtonFrame(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
const QHash<QByteArray, bool> &stateProperties,
|
||
|
qreal bgAnimation,
|
||
|
qreal penAnimation) const
|
||
|
{
|
||
|
bool enabled = stateProperties.value("enabled", true);
|
||
|
bool visualFocus = stateProperties.value("visualFocus");
|
||
|
bool hovered = stateProperties.value("hovered");
|
||
|
bool down = stateProperties.value("down");
|
||
|
bool checked = stateProperties.value("checked");
|
||
|
bool flat = stateProperties.value("flat");
|
||
|
bool defaultButton = stateProperties.value("defaultButton");
|
||
|
bool hasNeutralHighlight = stateProperties.value("hasNeutralHighlight");
|
||
|
bool isActiveWindow = stateProperties.value("isActiveWindow");
|
||
|
|
||
|
// don't render background if flat and not hovered, down, checked, or given visual focus
|
||
|
if (flat && !(hovered || down || checked || visualFocus) && bgAnimation == AnimationData::OpacityInvalid && penAnimation == AnimationData::OpacityInvalid) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QRectF shadowedRect = this->shadowedRect(rect);
|
||
|
QRectF frameRect = strokedRect(shadowedRect);
|
||
|
qreal radius = frameRadius(PenWidth::Frame);
|
||
|
// setting color group to work around KColorScheme feature
|
||
|
const QColor &highlightColor = palette.color(!enabled ? QPalette::Disabled : QPalette::Active, QPalette::Highlight);
|
||
|
QBrush bgBrush;
|
||
|
QBrush penBrush;
|
||
|
|
||
|
// Colors
|
||
|
if (flat) {
|
||
|
if (down && enabled) {
|
||
|
bgBrush = alphaColor(highlightColor, highlightBackgroundAlpha);
|
||
|
} else if (checked) {
|
||
|
bgBrush = hasNeutralHighlight ? alphaColor(neutralText(palette), highlightBackgroundAlpha) : alphaColor(palette.buttonText().color(), 0.125);
|
||
|
penBrush =
|
||
|
hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), Metrics::Bias_Default);
|
||
|
} else if (isActiveWindow && defaultButton) {
|
||
|
bgBrush = alphaColor(highlightColor, 0.125);
|
||
|
penBrush = KColorUtils::mix(highlightColor, KColorUtils::mix(palette.button().color(), palette.buttonText().color(), Metrics::Bias_Default), 0.5);
|
||
|
} else {
|
||
|
bgBrush = alphaColor(highlightColor, 0);
|
||
|
penBrush = hasNeutralHighlight ? neutralText(palette) : bgBrush;
|
||
|
}
|
||
|
} else {
|
||
|
if (down && enabled) {
|
||
|
bgBrush = KColorUtils::mix(palette.button().color(), highlightColor, 0.333);
|
||
|
} else if (checked) {
|
||
|
bgBrush = hasNeutralHighlight ? KColorUtils::mix(palette.button().color(), neutralText(palette), 0.333)
|
||
|
: KColorUtils::mix(palette.button().color(), palette.buttonText().color(), 0.125);
|
||
|
penBrush =
|
||
|
hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), Metrics::Bias_Default);
|
||
|
} else if (isActiveWindow && defaultButton) {
|
||
|
bgBrush = KColorUtils::mix(palette.button().color(), highlightColor, 0.2);
|
||
|
penBrush = KColorUtils::mix(highlightColor, KColorUtils::mix(palette.button().color(), palette.buttonText().color(), Metrics::Bias_Default), 0.5);
|
||
|
} else {
|
||
|
bgBrush = palette.button().color();
|
||
|
penBrush =
|
||
|
hasNeutralHighlight ? neutralText(palette) : KColorUtils::mix(palette.button().color(), palette.buttonText().color(), Metrics::Bias_Default);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((hovered || visualFocus || down) && enabled) {
|
||
|
penBrush = highlightColor;
|
||
|
}
|
||
|
|
||
|
// Animations
|
||
|
if (bgAnimation != AnimationData::OpacityInvalid && enabled) {
|
||
|
QColor color1 = bgBrush.color();
|
||
|
QColor color2 = flat ? alphaColor(highlightColor, highlightBackgroundAlpha) : KColorUtils::mix(palette.button().color(), highlightColor, 0.333);
|
||
|
bgBrush = KColorUtils::mix(color1, color2, bgAnimation);
|
||
|
}
|
||
|
if (penAnimation != AnimationData::OpacityInvalid && enabled) {
|
||
|
QColor color1 = penBrush.color();
|
||
|
QColor color2 = highlightColor;
|
||
|
penBrush = KColorUtils::mix(color1, color2, penAnimation);
|
||
|
}
|
||
|
|
||
|
// Shadow
|
||
|
if (isActiveWindow && !(flat || down || checked) && enabled) {
|
||
|
renderRoundedRectShadow(painter, shadowedRect, shadowColor(palette));
|
||
|
}
|
||
|
|
||
|
// Render button
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
painter->setBrush(bgBrush);
|
||
|
painter->setPen(QPen(penBrush, PenWidth::Frame));
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderToolBoxFrame(QPainter *painter, const QRect &rect, int tabWidth, const QColor &outline) const
|
||
|
{
|
||
|
if (!outline.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// round radius
|
||
|
const qreal radius(frameRadius(PenWidth::Frame));
|
||
|
const QSizeF cornerSize(2 * radius, 2 * radius);
|
||
|
|
||
|
// if rect - tabwidth is even, need to increase tabWidth by 1 unit
|
||
|
// for anti aliasing
|
||
|
if (!((rect.width() - tabWidth) % 2)) {
|
||
|
++tabWidth;
|
||
|
}
|
||
|
|
||
|
// adjust rect for antialiasing
|
||
|
QRectF baseRect(strokedRect(rect));
|
||
|
|
||
|
// create path
|
||
|
QPainterPath path;
|
||
|
path.moveTo(0, baseRect.height() - 1);
|
||
|
path.lineTo((baseRect.width() - tabWidth) / 2 - radius, baseRect.height() - 1);
|
||
|
path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2 - 2 * radius, baseRect.height() - 1 - 2 * radius), cornerSize), 270, 90);
|
||
|
path.lineTo((baseRect.width() - tabWidth) / 2, radius);
|
||
|
path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2, 0), cornerSize), 180, -90);
|
||
|
path.lineTo((baseRect.width() + tabWidth) / 2 - 1 - radius, 0);
|
||
|
path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1 - 2 * radius, 0), cornerSize), 90, -90);
|
||
|
path.lineTo((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - radius);
|
||
|
path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - 2 * radius), cornerSize), 180, 90);
|
||
|
path.lineTo(baseRect.width() - 1, baseRect.height() - 1);
|
||
|
|
||
|
// render
|
||
|
painter->setRenderHints(QPainter::Antialiasing);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->setPen(outline);
|
||
|
painter->translate(baseRect.topLeft());
|
||
|
painter->drawPath(path);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderTabWidgetFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Corners corners) const
|
||
|
{
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
|
||
|
QRectF frameRect(rect.adjusted(1, 1, -1, -1));
|
||
|
qreal radius(frameRadius(PenWidth::NoPen));
|
||
|
|
||
|
// set pen
|
||
|
if (outline.isValid()) {
|
||
|
painter->setPen(outline);
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
radius = frameRadiusForNewPenWidth(radius, PenWidth::Frame);
|
||
|
|
||
|
} else {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
}
|
||
|
|
||
|
// set brush
|
||
|
if (color.isValid()) {
|
||
|
painter->setBrush(color);
|
||
|
} else {
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
}
|
||
|
|
||
|
// render
|
||
|
QPainterPath path(roundedPath(frameRect, corners, radius));
|
||
|
painter->drawPath(path);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderSelection(QPainter *painter, const QRect &rect, const QColor &color) const
|
||
|
{
|
||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->setBrush(color);
|
||
|
painter->drawRect(rect);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderSeparator(QPainter *painter, const QRect &rect, const QColor &color, bool vertical) const
|
||
|
{
|
||
|
painter->setRenderHint(QPainter::Antialiasing, false);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->setPen(color);
|
||
|
|
||
|
if (vertical) {
|
||
|
painter->translate(rect.width() / 2, 0);
|
||
|
painter->drawLine(rect.topLeft(), rect.bottomLeft());
|
||
|
|
||
|
} else {
|
||
|
painter->translate(0, rect.height() / 2);
|
||
|
painter->drawLine(rect.topLeft(), rect.topRight());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderCheckBoxBackground(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
CheckBoxState state,
|
||
|
bool neutalHighlight,
|
||
|
bool sunken,
|
||
|
qreal animation) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
// copy rect
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.adjust(2, 2, -2, -2);
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
|
||
|
auto transparent = neutalHighlight ? neutralText(palette) : palette.highlight().color();
|
||
|
transparent.setAlphaF(highlightBackgroundAlpha);
|
||
|
|
||
|
QBrush penBrush;
|
||
|
if (neutalHighlight) {
|
||
|
penBrush = neutralText(palette);
|
||
|
} else if (state == CheckOn || state == CheckPartial) {
|
||
|
penBrush = palette.highlight().color();
|
||
|
} else {
|
||
|
penBrush = transparentize(palette.text().color(), Metrics::Bias_Default);
|
||
|
}
|
||
|
painter->setPen(QPen(penBrush, PenWidth::Frame));
|
||
|
|
||
|
const auto radius = Metrics::CheckBox_Radius;
|
||
|
|
||
|
switch (state) {
|
||
|
case CheckOff:
|
||
|
painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
break;
|
||
|
|
||
|
case CheckPartial:
|
||
|
case CheckOn:
|
||
|
painter->setBrush(transparent.darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
break;
|
||
|
|
||
|
case CheckAnimated:
|
||
|
painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
painter->setBrush(transparent);
|
||
|
painter->setOpacity(animation);
|
||
|
painter->drawRoundedRect(frameRect, radius, radius);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderCheckBox(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
bool mouseOver,
|
||
|
CheckBoxState state,
|
||
|
CheckBoxState target,
|
||
|
bool neutalHighlight,
|
||
|
bool sunken,
|
||
|
qreal animation,
|
||
|
qreal hoverAnimation) const
|
||
|
{
|
||
|
Q_UNUSED(sunken)
|
||
|
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
// copy rect and radius
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.adjust(2, 2, -2, -2);
|
||
|
|
||
|
if (mouseOver) {
|
||
|
painter->save();
|
||
|
|
||
|
if (hoverAnimation != AnimationData::OpacityInvalid) {
|
||
|
painter->setOpacity(hoverAnimation);
|
||
|
}
|
||
|
|
||
|
painter->setPen(QPen(neutalHighlight ? neutralText(palette).lighter() : focusColor(palette), PenWidth::Frame));
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
|
||
|
painter->drawRoundedRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5), Metrics::CheckBox_Radius, Metrics::CheckBox_Radius);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
// check
|
||
|
auto leftPoint = frameRect.center();
|
||
|
leftPoint.setX(frameRect.left() + 4);
|
||
|
|
||
|
auto bottomPoint = frameRect.center();
|
||
|
bottomPoint.setX(bottomPoint.x() - 1);
|
||
|
bottomPoint.setY(frameRect.bottom() - 5);
|
||
|
|
||
|
auto rightPoint = frameRect.center();
|
||
|
rightPoint.setX(rightPoint.x() + 4.5);
|
||
|
rightPoint.setY(frameRect.top() + 5.5);
|
||
|
|
||
|
QPainterPath path;
|
||
|
path.moveTo(leftPoint);
|
||
|
path.lineTo(bottomPoint);
|
||
|
path.lineTo(rightPoint);
|
||
|
|
||
|
// dots
|
||
|
auto centerDot = QRectF(frameRect.center(), QSize(2, 2));
|
||
|
centerDot.adjust(-1, -1, -1, -1);
|
||
|
auto leftDot = centerDot.adjusted(-4, 0, -4, 0);
|
||
|
auto rightDot = centerDot.adjusted(4, 0, 4, 0);
|
||
|
|
||
|
painter->setPen(Qt::transparent);
|
||
|
painter->setBrush(Qt::transparent);
|
||
|
|
||
|
auto checkPen = QPen(palette.text(), PenWidth::Frame * 2);
|
||
|
checkPen.setJoinStyle(Qt::MiterJoin);
|
||
|
|
||
|
switch (state) {
|
||
|
case CheckOff:
|
||
|
break;
|
||
|
case CheckOn:
|
||
|
painter->setPen(checkPen);
|
||
|
painter->drawPath(path);
|
||
|
break;
|
||
|
case CheckPartial:
|
||
|
painter->setBrush(palette.text());
|
||
|
painter->drawRect(leftDot);
|
||
|
painter->drawRect(centerDot);
|
||
|
painter->drawRect(rightDot);
|
||
|
break;
|
||
|
case CheckAnimated:
|
||
|
checkPen.setDashPattern({path.length() * animation, path.length()});
|
||
|
|
||
|
switch (target) {
|
||
|
case CheckOff:
|
||
|
break;
|
||
|
case CheckOn:
|
||
|
painter->setPen(checkPen);
|
||
|
painter->drawPath(path);
|
||
|
break;
|
||
|
case CheckPartial:
|
||
|
if (animation >= 3 / 3) {
|
||
|
painter->drawRect(rightDot);
|
||
|
}
|
||
|
if (animation >= 2 / 3) {
|
||
|
painter->drawRect(centerDot);
|
||
|
}
|
||
|
if (animation >= 1 / 3) {
|
||
|
painter->drawRect(leftDot);
|
||
|
}
|
||
|
break;
|
||
|
case CheckAnimated:
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderRadioButtonBackground(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
RadioButtonState state,
|
||
|
bool neutalHighlight,
|
||
|
bool sunken,
|
||
|
qreal animation) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
// copy rect
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.adjust(2, 2, -2, -2);
|
||
|
frameRect.adjust(0.5, 0.5, -0.5, -0.5);
|
||
|
|
||
|
auto transparent = neutalHighlight ? neutralText(palette) : palette.highlight().color();
|
||
|
transparent.setAlphaF(highlightBackgroundAlpha);
|
||
|
|
||
|
QBrush penBrush;
|
||
|
if (neutalHighlight) {
|
||
|
penBrush = neutralText(palette);
|
||
|
} else if (state == RadioOn) {
|
||
|
penBrush = palette.highlight().color();
|
||
|
} else {
|
||
|
penBrush = transparentize(palette.text().color(), Metrics::Bias_Default);
|
||
|
}
|
||
|
painter->setPen(QPen(penBrush, PenWidth::Frame));
|
||
|
|
||
|
switch (state) {
|
||
|
case RadioOff:
|
||
|
painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawEllipse(frameRect);
|
||
|
break;
|
||
|
case RadioOn:
|
||
|
painter->setBrush(transparent.darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawEllipse(frameRect);
|
||
|
break;
|
||
|
case RadioAnimated:
|
||
|
painter->setBrush(palette.base().color().darker(sunken ? radioCheckSunkenDarkeningFactor : 100));
|
||
|
painter->drawEllipse(frameRect);
|
||
|
painter->setBrush(transparent);
|
||
|
painter->setOpacity(animation);
|
||
|
painter->drawEllipse(frameRect);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderRadioButton(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
bool mouseOver,
|
||
|
RadioButtonState state,
|
||
|
bool neutralHighlight,
|
||
|
bool sunken,
|
||
|
qreal animation,
|
||
|
qreal animationHover) const
|
||
|
{
|
||
|
Q_UNUSED(sunken)
|
||
|
|
||
|
// copy rect
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.adjust(1, 1, -1, -1);
|
||
|
|
||
|
if (mouseOver) {
|
||
|
painter->save();
|
||
|
|
||
|
if (animationHover != AnimationData::OpacityInvalid) {
|
||
|
painter->setOpacity(animationHover);
|
||
|
}
|
||
|
|
||
|
painter->setPen(QPen(neutralHighlight ? neutralText(palette).lighter() : focusColor(palette), PenWidth::Frame));
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
|
||
|
const QRectF contentRect(frameRect.adjusted(1, 1, -1, -1).adjusted(0.5, 0.5, -0.5, -0.5));
|
||
|
painter->drawEllipse(contentRect);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
painter->setBrush(palette.text());
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
|
||
|
QRectF markerRect;
|
||
|
markerRect = frameRect.adjusted(6, 6, -6, -6);
|
||
|
|
||
|
qreal adjustFactor;
|
||
|
|
||
|
// mark
|
||
|
switch (state) {
|
||
|
case RadioOn:
|
||
|
painter->drawEllipse(markerRect);
|
||
|
|
||
|
break;
|
||
|
case RadioAnimated:
|
||
|
adjustFactor = markerRect.height() * (1 - animation);
|
||
|
markerRect.adjust(adjustFactor, adjustFactor, -adjustFactor, -adjustFactor);
|
||
|
painter->drawEllipse(markerRect);
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderSliderGroove(QPainter *painter, const QRect &rect, const QColor &color) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
QRectF baseRect(rect);
|
||
|
baseRect.adjust(0.5, 0.5, -0.5, -0.5);
|
||
|
const qreal radius(0.5 * Metrics::Slider_GrooveThickness);
|
||
|
|
||
|
// content
|
||
|
if (color.isValid()) {
|
||
|
painter->setPen(QPen(color, PenWidth::Frame));
|
||
|
auto bg = color;
|
||
|
bg.setAlphaF(bg.alphaF() / 2);
|
||
|
painter->setBrush(bg);
|
||
|
painter->drawRoundedRect(baseRect, radius, radius);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderDialGroove(QPainter *painter, const QRect &rect, const QColor &fg, const QColor &bg, qreal first, qreal last) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
const QRectF baseRect(rect);
|
||
|
|
||
|
// content
|
||
|
if (fg.isValid()) {
|
||
|
const qreal penWidth(Metrics::Slider_GrooveThickness);
|
||
|
const QRectF grooveRect(rect.adjusted(penWidth / 2, penWidth / 2, -penWidth / 2, -penWidth / 2));
|
||
|
|
||
|
// setup angles
|
||
|
const int angleStart(first * 180 * 16 / M_PI);
|
||
|
const int angleSpan((last - first) * 180 * 16 / M_PI);
|
||
|
|
||
|
const QPen bgPen(fg, penWidth, Qt::SolidLine, Qt::RoundCap);
|
||
|
const QPen fgPen(KColorUtils::overlayColors(bg, alphaColor(fg, 0.5)), penWidth - 2, Qt::SolidLine, Qt::RoundCap);
|
||
|
|
||
|
// setup pen
|
||
|
if (angleSpan != 0) {
|
||
|
painter->setPen(bgPen);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->drawArc(grooveRect, angleStart, angleSpan);
|
||
|
painter->setPen(fgPen);
|
||
|
painter->drawArc(grooveRect, angleStart, angleSpan);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::initSliderStyleOption(const QSlider *slider, QStyleOptionSlider *option) const
|
||
|
{
|
||
|
option->initFrom(slider);
|
||
|
option->subControls = QStyle::SC_None;
|
||
|
option->activeSubControls = QStyle::SC_None;
|
||
|
option->orientation = slider->orientation();
|
||
|
option->maximum = slider->maximum();
|
||
|
option->minimum = slider->minimum();
|
||
|
option->tickPosition = slider->tickPosition();
|
||
|
option->tickInterval = slider->tickInterval();
|
||
|
option->upsideDown = (slider->orientation() == Qt::Horizontal) //
|
||
|
? (slider->invertedAppearance() != (option->direction == Qt::RightToLeft))
|
||
|
: (!slider->invertedAppearance());
|
||
|
option->direction = Qt::LeftToRight; // we use the upsideDown option instead
|
||
|
option->sliderPosition = slider->sliderPosition();
|
||
|
option->sliderValue = slider->value();
|
||
|
option->singleStep = slider->singleStep();
|
||
|
option->pageStep = slider->pageStep();
|
||
|
if (slider->orientation() == Qt::Horizontal) {
|
||
|
option->state |= QStyle::State_Horizontal;
|
||
|
}
|
||
|
// Can't fetch activeSubControls, because it's private API
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QRectF Helper::pathForSliderHandleFocusFrame(QPainterPath &focusFramePath, const QRect &rect, int hmargin, int vmargin) const
|
||
|
{
|
||
|
// Mimics path and adjustments of renderSliderHandle
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.translate(hmargin, vmargin);
|
||
|
frameRect.adjust(1, 1, -1, -1);
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
focusFramePath.addEllipse(frameRect);
|
||
|
frameRect.adjust(-hmargin, -vmargin, hmargin, vmargin);
|
||
|
focusFramePath.addEllipse(frameRect);
|
||
|
return frameRect;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderSliderHandle(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow, bool sunken) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
// copy rect
|
||
|
QRectF frameRect(rect);
|
||
|
frameRect.adjust(1, 1, -1, -1);
|
||
|
|
||
|
// shadow
|
||
|
if (!sunken) {
|
||
|
renderEllipseShadow(painter, frameRect, shadow);
|
||
|
}
|
||
|
|
||
|
// set pen
|
||
|
if (outline.isValid()) {
|
||
|
painter->setPen(QPen(outline, PenWidth::Frame));
|
||
|
frameRect = strokedRect(frameRect);
|
||
|
|
||
|
} else {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
}
|
||
|
|
||
|
// set brush
|
||
|
if (color.isValid()) {
|
||
|
painter->setBrush(color);
|
||
|
} else {
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
}
|
||
|
|
||
|
// render
|
||
|
painter->drawEllipse(frameRect);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderProgressBarGroove(QPainter *painter, const QRect &rect, const QColor &fg, const QColor &bg) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
QRectF baseRect(rect);
|
||
|
baseRect.adjust(0.5, 0.5, -0.5, -0.5);
|
||
|
const qreal radius(0.5 * Metrics::ProgressBar_Thickness);
|
||
|
|
||
|
// content
|
||
|
if (fg.isValid()) {
|
||
|
painter->setPen(QPen(fg, PenWidth::Frame));
|
||
|
painter->setBrush(KColorUtils::overlayColors(bg, alphaColor(fg, 0.5)));
|
||
|
painter->drawRoundedRect(baseRect, radius, radius);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderProgressBarBusyContents(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QColor &first,
|
||
|
const QColor &second,
|
||
|
bool horizontal,
|
||
|
bool reverse,
|
||
|
int progress) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
const QRectF baseRect(rect);
|
||
|
const qreal radius(0.5 * Metrics::ProgressBar_Thickness);
|
||
|
|
||
|
// setup brush
|
||
|
QPixmap pixmap(horizontal ? 2 * Metrics::ProgressBar_BusyIndicatorSize : 1, horizontal ? 1 : 2 * Metrics::ProgressBar_BusyIndicatorSize);
|
||
|
pixmap.fill(second);
|
||
|
if (horizontal) {
|
||
|
QPainter painter(&pixmap);
|
||
|
painter.setBrush(first);
|
||
|
painter.setPen(Qt::NoPen);
|
||
|
|
||
|
progress %= 2 * Metrics::ProgressBar_BusyIndicatorSize;
|
||
|
if (reverse) {
|
||
|
progress = 2 * Metrics::ProgressBar_BusyIndicatorSize - progress - 1;
|
||
|
}
|
||
|
painter.drawRect(QRect(0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1).translated(progress, 0));
|
||
|
|
||
|
if (progress > Metrics::ProgressBar_BusyIndicatorSize) {
|
||
|
painter.drawRect(QRect(0, 0, Metrics::ProgressBar_BusyIndicatorSize, 1).translated(progress - 2 * Metrics::ProgressBar_BusyIndicatorSize, 0));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
QPainter painter(&pixmap);
|
||
|
painter.setBrush(first);
|
||
|
painter.setPen(Qt::NoPen);
|
||
|
|
||
|
progress %= 2 * Metrics::ProgressBar_BusyIndicatorSize;
|
||
|
progress = 2 * Metrics::ProgressBar_BusyIndicatorSize - progress - 1;
|
||
|
painter.drawRect(QRect(0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize).translated(0, progress));
|
||
|
|
||
|
if (progress > Metrics::ProgressBar_BusyIndicatorSize) {
|
||
|
painter.drawRect(QRect(0, 0, 1, Metrics::ProgressBar_BusyIndicatorSize).translated(0, progress - 2 * Metrics::ProgressBar_BusyIndicatorSize));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->setBrush(pixmap);
|
||
|
painter->drawRoundedRect(baseRect, radius, radius);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderScrollBarHandle(QPainter *painter, const QRect &rect, const QColor &fg, const QColor &bg) const
|
||
|
{
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
const QRectF baseRect(rect);
|
||
|
const qreal radius(0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth}));
|
||
|
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->setPen(QPen(fg, 1.001));
|
||
|
painter->setBrush(KColorUtils::overlayColors(bg, alphaColor(fg, 0.5)));
|
||
|
painter->drawRoundedRect(strokedRect(baseRect), radius, radius);
|
||
|
}
|
||
|
|
||
|
void Helper::renderScrollBarGroove(QPainter *painter, const QRect &rect, const QColor &color) const
|
||
|
{
|
||
|
// check for negative size, possible with squeezed controls
|
||
|
if (!rect.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
const QRectF baseRect(rect);
|
||
|
const qreal radius(0.5 * std::min({baseRect.width(), baseRect.height(), (qreal)Metrics::ScrollBar_SliderWidth}));
|
||
|
|
||
|
// content
|
||
|
if (color.isValid()) {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
auto bg = color;
|
||
|
bg.setAlphaF(bg.alphaF() / 2.0);
|
||
|
painter->setBrush(bg);
|
||
|
painter->setPen(QPen(color, 1.001));
|
||
|
painter->drawRoundedRect(strokedRect(baseRect), radius, radius);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderScrollBarBorder(QPainter *painter, const QRect &rect, const QColor &color) const
|
||
|
{
|
||
|
// content
|
||
|
if (color.isValid()) {
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->setBrush(color);
|
||
|
painter->drawRect(rect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderTabBarTab(QPainter *painter,
|
||
|
const QRect &rect,
|
||
|
const QPalette &palette,
|
||
|
const QHash<QByteArray, bool> &stateProperties,
|
||
|
Corners corners,
|
||
|
qreal animation) const
|
||
|
{
|
||
|
bool enabled = stateProperties.value("enabled", true);
|
||
|
bool hovered = stateProperties.value("hovered");
|
||
|
bool selected = stateProperties.value("selected");
|
||
|
bool documentMode = stateProperties.value("documentMode");
|
||
|
bool north = stateProperties.value("north");
|
||
|
bool south = stateProperties.value("south");
|
||
|
bool west = stateProperties.value("west");
|
||
|
bool east = stateProperties.value("east");
|
||
|
bool animated = animation != AnimationData::OpacityInvalid;
|
||
|
bool isQtQuickControl = stateProperties.value("isQtQuickControl");
|
||
|
bool hasAlteredBackground = stateProperties.value("hasAlteredBackground");
|
||
|
|
||
|
// setup painter
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
QRectF frameRect = rect;
|
||
|
QColor bgBrush;
|
||
|
|
||
|
if (selected) {
|
||
|
if (north) {
|
||
|
// overlap bottom border
|
||
|
frameRect.adjust(0, 0, 0, 1);
|
||
|
} else if (south) {
|
||
|
// overlap top border
|
||
|
frameRect.adjust(0, -1, 0, 0);
|
||
|
} else if (west) {
|
||
|
// overlap right border
|
||
|
frameRect.adjust(0, 0, 1, 0);
|
||
|
} else if (east) {
|
||
|
// overlap left border
|
||
|
frameRect.adjust(-1, 0, 0, 0);
|
||
|
}
|
||
|
if (documentMode && !isQtQuickControl && !hasAlteredBackground) {
|
||
|
bgBrush = palette.color(QPalette::Window);
|
||
|
} else {
|
||
|
bgBrush = frameBackgroundColor(palette);
|
||
|
}
|
||
|
QColor penBrush = KColorUtils::mix(bgBrush, palette.color(QPalette::WindowText), Metrics::Bias_Default);
|
||
|
painter->setBrush(bgBrush);
|
||
|
painter->setPen(QPen(penBrush, PenWidth::Frame));
|
||
|
QRectF highlightRect = frameRect;
|
||
|
if (north || south) {
|
||
|
highlightRect.setHeight(Metrics::Frame_FrameRadius);
|
||
|
} else if (west || east) {
|
||
|
highlightRect.setWidth(Metrics::Frame_FrameRadius);
|
||
|
}
|
||
|
if (south) {
|
||
|
highlightRect.moveBottom(frameRect.bottom());
|
||
|
} else if (east) {
|
||
|
highlightRect.moveRight(frameRect.right());
|
||
|
}
|
||
|
QPainterPath path = roundedPath(strokedRect(frameRect), corners, frameRadius(PenWidth::Frame));
|
||
|
painter->drawPath(path);
|
||
|
QPainterPath highlightPath = roundedPath(highlightRect, corners, Metrics::Frame_FrameRadius);
|
||
|
painter->setBrush(palette.color(QPalette::Highlight));
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->drawPath(highlightPath);
|
||
|
} else {
|
||
|
if (north) {
|
||
|
// don't overlap bottom border
|
||
|
frameRect.adjust(0, 0, 0, -1);
|
||
|
} else if (south) {
|
||
|
// don't overlap top border
|
||
|
frameRect.adjust(0, 1, 0, 0);
|
||
|
} else if (west) {
|
||
|
// don't overlap right border
|
||
|
frameRect.adjust(0, 0, -1, 0);
|
||
|
} else if (east) {
|
||
|
// don't overlap left border
|
||
|
frameRect.adjust(1, 0, 0, 0);
|
||
|
}
|
||
|
const auto windowColor = palette.color(QPalette::Window);
|
||
|
bgBrush = windowColor.darker(120);
|
||
|
const auto hover = alphaColor(hoverColor(palette), 0.2);
|
||
|
if (animated) {
|
||
|
bgBrush = KColorUtils::mix(bgBrush, hover, animation);
|
||
|
} else if (enabled && hovered && !selected) {
|
||
|
bgBrush = hover;
|
||
|
}
|
||
|
painter->setBrush(bgBrush);
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
QPainterPath path = roundedPath(frameRect, corners, Metrics::Frame_FrameRadius);
|
||
|
painter->drawPath(path);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderArrow(QPainter *painter, const QRect &rect, const QColor &color, ArrowOrientation orientation) const
|
||
|
{
|
||
|
int size = std::min({rect.width(), rect.height(), Metrics::ArrowSize});
|
||
|
// No point in trying to draw if it's too small
|
||
|
if (size <= 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
qreal penOffset = PenWidth::Symbol / 2.0;
|
||
|
qreal center = size / 2.0;
|
||
|
qreal maxExtent = size * 0.75;
|
||
|
qreal minExtent = size / 4.0;
|
||
|
qreal sizeOffset = 0;
|
||
|
int remainder = size % 4;
|
||
|
if (remainder == 2) {
|
||
|
sizeOffset = 0.5;
|
||
|
} else if (remainder == 1) {
|
||
|
sizeOffset = -0.25;
|
||
|
} else if (remainder == 3) {
|
||
|
sizeOffset = 0.25;
|
||
|
}
|
||
|
|
||
|
QPolygonF arrow;
|
||
|
switch (orientation) {
|
||
|
case ArrowUp:
|
||
|
arrow = QVector<QPointF>{
|
||
|
{penOffset, maxExtent - penOffset - sizeOffset}, // left
|
||
|
{center, minExtent - sizeOffset}, // mid
|
||
|
{size - penOffset, maxExtent - penOffset - sizeOffset} // right
|
||
|
};
|
||
|
break;
|
||
|
case ArrowDown:
|
||
|
arrow = QVector<QPointF>{
|
||
|
{penOffset, minExtent + penOffset + sizeOffset}, // left
|
||
|
{center, maxExtent + sizeOffset}, // mid
|
||
|
{size - penOffset, minExtent + penOffset + sizeOffset} // right
|
||
|
};
|
||
|
break;
|
||
|
case ArrowLeft:
|
||
|
arrow = QVector<QPointF>{
|
||
|
{maxExtent - penOffset - sizeOffset, penOffset}, // top
|
||
|
{minExtent - sizeOffset, center}, // mid
|
||
|
{maxExtent - penOffset - sizeOffset, size - penOffset}, // bottom
|
||
|
};
|
||
|
break;
|
||
|
case ArrowRight:
|
||
|
arrow = QVector<QPointF>{
|
||
|
{minExtent + penOffset + sizeOffset, penOffset}, // top
|
||
|
{maxExtent + sizeOffset, center}, // mid
|
||
|
{minExtent + penOffset + sizeOffset, size - penOffset}, // bottom
|
||
|
};
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
arrow.translate(rect.x() + (rect.width() - size) / 2.0, rect.y() + (rect.height() - size) / 2.0);
|
||
|
|
||
|
painter->save();
|
||
|
painter->setRenderHints(QPainter::Antialiasing);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
QPen pen(color, PenWidth::Symbol);
|
||
|
pen.setCapStyle(Qt::SquareCap);
|
||
|
pen.setJoinStyle(Qt::MiterJoin);
|
||
|
painter->setPen(pen);
|
||
|
painter->drawPolyline(arrow);
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderDecorationButton(QPainter *painter, const QRect &rect, const QColor &color, ButtonType buttonType, bool inverted) const
|
||
|
{
|
||
|
painter->save();
|
||
|
painter->setViewport(rect);
|
||
|
painter->setWindow(0, 0, 18, 18);
|
||
|
painter->setRenderHints(QPainter::Antialiasing);
|
||
|
|
||
|
// initialize pen
|
||
|
QPen pen;
|
||
|
pen.setCapStyle(Qt::RoundCap);
|
||
|
pen.setJoinStyle(Qt::MiterJoin);
|
||
|
|
||
|
if (inverted) {
|
||
|
// render circle
|
||
|
painter->setPen(Qt::NoPen);
|
||
|
painter->setBrush(color);
|
||
|
painter->drawEllipse(QRectF(0, 0, 18, 18));
|
||
|
|
||
|
// take out the inner part
|
||
|
painter->setCompositionMode(QPainter::CompositionMode_DestinationOut);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
pen.setColor(Qt::black);
|
||
|
|
||
|
} else {
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
pen.setColor(color);
|
||
|
}
|
||
|
|
||
|
pen.setCapStyle(Qt::RoundCap);
|
||
|
pen.setJoinStyle(Qt::MiterJoin);
|
||
|
pen.setWidthF(PenWidth::Symbol * qMax(1.0, 18.0 / rect.width()));
|
||
|
painter->setPen(pen);
|
||
|
|
||
|
switch (buttonType) {
|
||
|
case ButtonClose: {
|
||
|
painter->drawLine(QPointF(5, 5), QPointF(13, 13));
|
||
|
painter->drawLine(13, 5, 5, 13);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ButtonMaximize: {
|
||
|
painter->drawPolyline(QVector<QPointF>{QPointF(4, 11), QPointF(9, 6), QPointF(14, 11)});
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ButtonMinimize: {
|
||
|
painter->drawPolyline(QVector<QPointF>{QPointF(4, 7), QPointF(9, 12), QPointF(14, 7)});
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case ButtonRestore: {
|
||
|
pen.setJoinStyle(Qt::RoundJoin);
|
||
|
painter->setPen(pen);
|
||
|
painter->drawPolygon(QVector<QPointF>{QPointF(4.5, 9), QPointF(9, 4.5), QPointF(13.5, 9), QPointF(9, 13.5)});
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderRoundedRectShadow(QPainter *painter, const QRectF &rect, const QColor &color, qreal radius) const
|
||
|
{
|
||
|
if (!color.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||
|
|
||
|
qreal adjustment = 0.5 * PenWidth::Shadow; // Translate for the pen
|
||
|
QRectF shadowRect = rect.adjusted(adjustment, adjustment, -adjustment, adjustment);
|
||
|
|
||
|
painter->setPen(QPen(color, PenWidth::Shadow));
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->drawRoundedRect(shadowRect, radius, radius);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
void Helper::renderEllipseShadow(QPainter *painter, const QRectF &rect, const QColor &color) const
|
||
|
{
|
||
|
if (!color.isValid()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
painter->save();
|
||
|
|
||
|
// Clipping does not improve performance here
|
||
|
|
||
|
qreal adjustment = 0.5 * PenWidth::Shadow; // Adjust for the pen
|
||
|
|
||
|
qreal radius = rect.width() / 2 - adjustment;
|
||
|
|
||
|
/* The right side is offset by +0.5 for the visible part of the shadow.
|
||
|
* The other sides are offset by +0.5 or -0.5 because of the pen.
|
||
|
*/
|
||
|
QRectF shadowRect = rect.adjusted(adjustment, adjustment, adjustment, -adjustment);
|
||
|
|
||
|
painter->translate(rect.center());
|
||
|
painter->rotate(45);
|
||
|
painter->translate(-rect.center());
|
||
|
painter->setPen(color);
|
||
|
painter->setBrush(Qt::NoBrush);
|
||
|
painter->drawRoundedRect(shadowRect, radius, radius);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
bool Helper::isX11()
|
||
|
{
|
||
|
static const bool s_isX11 = KWindowSystem::isPlatformX11();
|
||
|
return s_isX11;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
bool Helper::isWayland()
|
||
|
{
|
||
|
static const bool s_isWayland = KWindowSystem::isPlatformWayland();
|
||
|
return s_isWayland;
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QRectF Helper::strokedRect(const QRectF &rect, const qreal penWidth) const
|
||
|
{
|
||
|
/* With a pen stroke width of 1, the rectangle should have each of its
|
||
|
* sides moved inwards by half a pixel. This allows the stroke to be
|
||
|
* pixel perfect instead of blurry from sitting between pixels and
|
||
|
* prevents the rectangle with a stroke from becoming larger than the
|
||
|
* original size of the rectangle.
|
||
|
*/
|
||
|
qreal adjustment = 0.5 * penWidth;
|
||
|
return rect.adjusted(adjustment, adjustment, -adjustment, -adjustment);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________
|
||
|
QPainterPath Helper::roundedPath(const QRectF &rect, Corners corners, qreal radius) const
|
||
|
{
|
||
|
QPainterPath path;
|
||
|
|
||
|
// simple cases
|
||
|
if (corners == 0) {
|
||
|
path.addRect(rect);
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
if (corners == AllCorners) {
|
||
|
path.addRoundedRect(rect, radius, radius);
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
const QSizeF cornerSize(2 * radius, 2 * radius);
|
||
|
|
||
|
// rotate counterclockwise
|
||
|
// top left corner
|
||
|
if (corners & CornerTopLeft) {
|
||
|
path.moveTo(rect.topLeft() + QPointF(radius, 0));
|
||
|
path.arcTo(QRectF(rect.topLeft(), cornerSize), 90, 90);
|
||
|
|
||
|
} else {
|
||
|
path.moveTo(rect.topLeft());
|
||
|
}
|
||
|
|
||
|
// bottom left corner
|
||
|
if (corners & CornerBottomLeft) {
|
||
|
path.lineTo(rect.bottomLeft() - QPointF(0, radius));
|
||
|
path.arcTo(QRectF(rect.bottomLeft() - QPointF(0, 2 * radius), cornerSize), 180, 90);
|
||
|
|
||
|
} else {
|
||
|
path.lineTo(rect.bottomLeft());
|
||
|
}
|
||
|
|
||
|
// bottom right corner
|
||
|
if (corners & CornerBottomRight) {
|
||
|
path.lineTo(rect.bottomRight() - QPointF(radius, 0));
|
||
|
path.arcTo(QRectF(rect.bottomRight() - QPointF(2 * radius, 2 * radius), cornerSize), 270, 90);
|
||
|
|
||
|
} else {
|
||
|
path.lineTo(rect.bottomRight());
|
||
|
}
|
||
|
|
||
|
// top right corner
|
||
|
if (corners & CornerTopRight) {
|
||
|
path.lineTo(rect.topRight() + QPointF(0, radius));
|
||
|
path.arcTo(QRectF(rect.topRight() - QPointF(2 * radius, 0), cornerSize), 0, 90);
|
||
|
|
||
|
} else {
|
||
|
path.lineTo(rect.topRight());
|
||
|
}
|
||
|
|
||
|
path.closeSubpath();
|
||
|
return path;
|
||
|
}
|
||
|
|
||
|
//________________________________________________________________________________________________________
|
||
|
bool Helper::compositingActive() const
|
||
|
{
|
||
|
if (isX11()) {
|
||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
|
return KWindowSystem::compositingActive();
|
||
|
#elif __has_include(<KX11Extras>)
|
||
|
return KX11Extras::compositingActive();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//____________________________________________________________________
|
||
|
bool Helper::hasAlphaChannel(const QWidget *widget) const
|
||
|
{
|
||
|
return compositingActive() && widget && widget->testAttribute(Qt::WA_TranslucentBackground);
|
||
|
}
|
||
|
|
||
|
//______________________________________________________________________________________
|
||
|
|
||
|
QPixmap Helper::coloredIcon(const QIcon &icon, const QPalette &palette, const QSize &size, qreal devicePixelRatio, QIcon::Mode mode, QIcon::State state)
|
||
|
{
|
||
|
const QPalette activePalette = KIconLoader::global()->customPalette();
|
||
|
const bool changePalette = activePalette != palette;
|
||
|
if (changePalette) {
|
||
|
KIconLoader::global()->setCustomPalette(palette);
|
||
|
}
|
||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||
|
const QPixmap pixmap = icon.pixmap(size, devicePixelRatio, mode, state);
|
||
|
#else
|
||
|
Q_UNUSED(devicePixelRatio);
|
||
|
const QPixmap pixmap = icon.pixmap(size, mode, state);
|
||
|
#endif
|
||
|
if (changePalette) {
|
||
|
if (activePalette == QPalette()) {
|
||
|
KIconLoader::global()->resetPalette();
|
||
|
} else {
|
||
|
KIconLoader::global()->setCustomPalette(activePalette);
|
||
|
}
|
||
|
}
|
||
|
return pixmap;
|
||
|
}
|
||
|
|
||
|
bool Helper::shouldDrawToolsArea(const QWidget *widget) const
|
||
|
{
|
||
|
if (!widget) {
|
||
|
return false;
|
||
|
}
|
||
|
static bool isAuto = false;
|
||
|
static QString borderSize;
|
||
|
if (!_cachedAutoValid) {
|
||
|
KConfigGroup kdecorationGroup(_kwinConfig->group(QStringLiteral("org.kde.kdecoration2")));
|
||
|
isAuto = kdecorationGroup.readEntry("BorderSizeAuto", true);
|
||
|
borderSize = kdecorationGroup.readEntry("BorderSize", "Normal");
|
||
|
_cachedAutoValid = true;
|
||
|
}
|
||
|
if (isAuto) {
|
||
|
auto window = widget->window();
|
||
|
if (qobject_cast<const QDialog *>(widget)) {
|
||
|
return true;
|
||
|
}
|
||
|
if (window) {
|
||
|
auto handle = window->windowHandle();
|
||
|
if (handle) {
|
||
|
auto toolbar = qobject_cast<const QToolBar *>(widget);
|
||
|
if (toolbar) {
|
||
|
if (toolbar->isFloating()) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if (borderSize != "None" && borderSize != "NoSides") {
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
Qt::Edges Helper::menuSeamlessEdges(const QWidget *widget)
|
||
|
{
|
||
|
if (widget) {
|
||
|
auto edges = widget->property(PropertyNames::menuSeamlessEdges).value<Qt::Edges>();
|
||
|
// Fallback to older property
|
||
|
if (edges == Qt::Edges() && widget->property(PropertyNames::isTopMenu).toBool()) {
|
||
|
edges = Qt::TopEdge;
|
||
|
}
|
||
|
return edges;
|
||
|
}
|
||
|
return Qt::Edges();
|
||
|
}
|
||
|
}
|