11#include "schememanager.h"
14#include <kconfiggroup.h>
25 explicit HCYColorSpace(
const QColor&);
26 explicit HCYColorSpace(qreal h_, qreal c_, qreal y_, qreal a_ = 1.0);
28 QColor qColor()
const;
30 static qreal luma(
const QColor &);
41 static qreal gamma(qreal);
42 static qreal igamma(qreal);
43 static qreal lumag(qreal, qreal, qreal);
51static inline qreal wrap(qreal a, qreal d = 1.0)
55 return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
62static inline qreal normalize(qreal a)
64 return (a < 1.0 ? (a > 0.0 ? a : 0.0) : 1.0);
67static inline qreal mixQreal(qreal a, qreal b, qreal bias)
69 return (a + (b - a) * bias);
78qreal luma(
const QColor& color)
80 return HCYColorSpace::luma(color);
86void getHcy(
const QColor& color, qreal* h, qreal* c, qreal* y, qreal* a = 0)
93 HCYColorSpace khcy(color);
114static qreal contrastRatioForLuma(qreal y1, qreal y2)
118 return (y1 + 0.05) / (y2 + 0.05);
121 return (y2 + 0.05) / (y1 + 0.05);
124qreal contrastRatio(
const QColor& c1,
const QColor& c2)
126 return contrastRatioForLuma(luma(c1), luma(c2));
132QColor lighten(
const QColor& color, qreal ky = 0.5, qreal kc = 1.0)
134 HCYColorSpace c(color);
135 c.y = 1.0 - ColorTools::normalize((1.0 - c.y) * (1.0 - ky));
136 c.c = 1.0 - ColorTools::normalize((1.0 - c.c) * kc);
144QColor darken(
const QColor& color, qreal ky = 0.5, qreal kc = 1.0)
146 HCYColorSpace c(color);
147 c.y = ColorTools::normalize(c.y * (1.0 - ky));
148 c.c = ColorTools::normalize(c.c * kc);
157QColor shade(
const QColor& color, qreal ky, qreal kc = 0.0)
159 HCYColorSpace c(color);
160 c.y = ColorTools::normalize(c.y + ky);
161 c.c = ColorTools::normalize(c.c + kc);
169QColor mix(
const QColor& c1,
const QColor& c2, qreal bias)
186 qreal r = mixQreal(c1.
redF(), c2.
redF(), bias);
188 qreal b = mixQreal(c1.
blueF(), c2.
blueF(), bias);
194static QColor tintHelper(
const QColor& base, qreal baseLuma,
const QColor& color, qreal amount)
196 HCYColorSpace result(mix(base, color, pow(amount, 0.3)));
197 result.y = mixQreal(baseLuma, result.y, amount);
199 return result.qColor();
214QColor tint(
const QColor& base,
const QColor& color, qreal amount = 0.3)
231 qreal baseLuma = luma(base);
232 double ri = contrastRatioForLuma(baseLuma, luma(color));
233 double rg = 1.0 + ((ri + 1.0) * amount * amount * amount);
234 double u = 1.0, l = 0.0;
237 for (
int i = 12; i; --i)
239 double a = 0.5 * (l + u);
240 result = tintHelper(base, baseLuma, color, a);
241 double ra = contrastRatioForLuma(baseLuma, luma(result));
264QColor overlayColors(
const QColor& base,
const QColor& paint,
273 p.fillRect(0, 0, 1, 1, start);
274 p.setCompositionMode(comp);
275 p.fillRect(0, 0, 1, 1, paint);
278 return img.pixel(0, 0);
287static const qreal yc[3] = {0.299, 0.587, 0.114 };
289static const qreal yc[3] = {0.2126, 0.7152, 0.0722 };
291static const qreal yc[3] = {0.34375, 0.5, 0.15625};
294qreal HCYColorSpace::gamma(qreal n)
296 return pow(ColorTools::normalize(n), 2.2);
299qreal HCYColorSpace::igamma(qreal n)
301 return pow(ColorTools::normalize(n), 1.0 / 2.2);
304qreal HCYColorSpace::lumag(qreal r, qreal g, qreal b)
306 return r * yc[0] + g * yc[1] + b * yc[2];
309HCYColorSpace::HCYColorSpace(qreal h_, qreal c_, qreal y_, qreal a_)
317HCYColorSpace::HCYColorSpace(
const QColor& color)
319 qreal r = gamma(color.
redF());
320 qreal g = gamma(color.
greenF());
321 qreal b = gamma(color.
blueF());
328 qreal p = qMax(qMax(r, g), b);
329 qreal n = qMin(qMin(r, g), b);
330 qreal d = 6.0 * (p - n);
342 h = ((b - r) / d) + (1.0 / 3.0);
346 h = ((r - g) / d) + (2.0 / 3.0);
350 if (r == g && g == b)
356 c = qMax((y - n) / y, (p - y) / (1 - y));
360QColor HCYColorSpace::qColor()
const
363 qreal _h = ColorTools::wrap(h);
364 qreal _c = ColorTools::normalize(c);
365 qreal _y = ColorTools::normalize(y);
368 qreal _hs = _h * 6.0, th, tm;
373 tm = yc[0] + yc[1] * th;
378 tm = yc[1] + yc[0] * th;
383 tm = yc[1] + yc[2] * th;
388 tm = yc[2] + yc[1] * th;
393 tm = yc[2] + yc[0] * th;
398 tm = yc[0] + yc[2] * th;
406 tp = _y + _y * _c * (1.0 - tm) / tm;
407 to = _y + _y * _c * (th - tm) / tm;
412 tp = _y + (1.0 - _y) * _c;
413 to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
414 tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
444qreal HCYColorSpace::luma(
const QColor& color)
446 return lumag(gamma(color.
redF()),
448 gamma(color.
blueF()));
458 ~StateEffects() =
default;
460 QBrush brush(
const QBrush& background)
const;
461 QBrush brush(
const QBrush& foreground,
const QBrush& background)
const;
472 IntensityNoEffect = 0,
475 IntensityLighten = 3,
482 ContrastNoEffect = 0,
514 KConfigGroup cfg(config, group);
515 const bool enabledByDefault = (state == QPalette::Disabled);
517 if (cfg.readEntry(
"Enable", enabledByDefault))
519 _effects[Intensity] = cfg.readEntry(
"IntensityEffect", (int)((state == QPalette::Disabled) ? IntensityDarken : IntensityNoEffect));
520 _effects[Color] = cfg.readEntry(
"ColorEffect", (int)((state == QPalette::Disabled) ? ColorNoEffect : ColorDesaturate));
521 _effects[Contrast] = cfg.readEntry(
"ContrastEffect", (int)((state == QPalette::Disabled) ? ContrastFade : ContrastTint));
522 _amount[Intensity] = cfg.readEntry(
"IntensityAmount", (state == QPalette::Disabled) ? 0.10 : 0.0);
523 _amount[Color] = cfg.readEntry(
"ColorAmount", (state == QPalette::Disabled) ? 0.0 : -0.9);
524 _amount[Contrast] = cfg.readEntry(
"ContrastAmount", (state == QPalette::Disabled) ? 0.65 : 0.25);
526 if (_effects[Color] > ColorNoEffect)
528 _color = cfg.readEntry(
"Color", (state == QPalette::Disabled) ? QColor(56, 56, 56)
529 : QColor(112, 111, 110));
535QBrush StateEffects::brush(
const QBrush& background)
const
537 QColor color = background.
color();
539 switch (_effects[Intensity])
542 color = ColorTools::shade(color, _amount[Intensity]);
544 case IntensityDarken:
545 color = ColorTools::darken(color, _amount[Intensity]);
547 case IntensityLighten:
548 color = ColorTools::lighten(color, _amount[Intensity]);
552 switch (_effects[Color])
554 case ColorDesaturate:
555 color = ColorTools::darken(color, 0.0, 1.0 - _amount[Color]);
558 color = ColorTools::mix(color, _color, _amount[Color]);
561 color = ColorTools::tint(color, _color, _amount[Color]);
565 return QBrush(color);
570 QColor color = foreground.
color();
571 QColor bg = background.
color();
575 switch (_effects[Contrast])
578 color = ColorTools::mix(color, bg, _amount[Contrast]);
581 color = ColorTools::tint(color, bg, _amount[Contrast]);
592struct SetDefaultColors
594 int NormalBackground[3];
595 int AlternateBackground[3];
606struct DecoDefaultColors
613static const SetDefaultColors defaultViewColors =
627static const SetDefaultColors defaultWindowColors =
641static const SetDefaultColors defaultButtonColors =
655static const SetDefaultColors defaultSelectionColors =
669static const SetDefaultColors defaultTooltipColors =
683static const SetDefaultColors defaultComplementaryColors =
697static const DecoDefaultColors defaultDecorationColors =
709 explicit SchemeManagerPrivate(
const KSharedConfigPtr&,
QPalette::ColorGroup,
const char*, SetDefaultColors);
710 explicit SchemeManagerPrivate(
const KSharedConfigPtr&,
QPalette::ColorGroup,
const char*, SetDefaultColors,
const QBrush&);
711 ~SchemeManagerPrivate() =
default;
716 qreal contrast()
const;
734#define DEFAULT(c) QColor( c[0], c[1], c[2] )
735#define SET_DEFAULT(a) DEFAULT( defaults.a )
736#define DECO_DEFAULT(a) DEFAULT( defaultDecorationColors.a )
738SchemeManagerPrivate::SchemeManagerPrivate(
const KSharedConfigPtr& config,
741 SetDefaultColors defaults)
743 KConfigGroup cfg(config, group);
747 _brushes.bg[0] = cfg.readEntry(
"BackgroundNormal", SET_DEFAULT(NormalBackground));
748 _brushes.bg[1] = cfg.readEntry(
"BackgroundAlternate", SET_DEFAULT(AlternateBackground));
751 init(config, state, group, defaults);
754SchemeManagerPrivate::SchemeManagerPrivate(
const KSharedConfigPtr& config,
757 SetDefaultColors defaults,
760 KConfigGroup cfg(config, group);
764 _brushes.bg[0] = cfg.readEntry(
"BackgroundNormal", SET_DEFAULT(NormalBackground));
765 _brushes.bg[1] = cfg.readEntry(
"BackgroundAlternate", SET_DEFAULT(AlternateBackground));
768 _brushes.bg[0] = ColorTools::tint(_brushes.bg[0].color(),
tint.color(), 0.4);
769 _brushes.bg[1] = ColorTools::tint(_brushes.bg[1].color(),
tint.color(), 0.4);
772 init(config, state, group, defaults);
775void SchemeManagerPrivate::init(
const KSharedConfigPtr& config,
778 SetDefaultColors defaults)
780 KConfigGroup cfg(config, group);
783 _brushes.fg[0] = cfg.readEntry(
"ForegroundNormal", SET_DEFAULT(NormalText));
784 _brushes.fg[1] = cfg.readEntry(
"ForegroundInactive", SET_DEFAULT(InactiveText));
785 _brushes.fg[2] = cfg.readEntry(
"ForegroundActive", SET_DEFAULT(ActiveText));
786 _brushes.fg[3] = cfg.readEntry(
"ForegroundLink", SET_DEFAULT(LinkText));
787 _brushes.fg[4] = cfg.readEntry(
"ForegroundVisited", SET_DEFAULT(VisitedText));
788 _brushes.fg[5] = cfg.readEntry(
"ForegroundNegative", SET_DEFAULT(NegativeText));
789 _brushes.fg[6] = cfg.readEntry(
"ForegroundNeutral", SET_DEFAULT(NeutralText));
790 _brushes.fg[7] = cfg.readEntry(
"ForegroundPositive", SET_DEFAULT(PositiveText));
791 _brushes.deco[0] = cfg.readEntry(
"DecorationHover", DECO_DEFAULT(Hover));
792 _brushes.deco[1] = cfg.readEntry(
"DecorationFocus", DECO_DEFAULT(Focus));
798 StateEffects effects(state, config);
800 for (
auto &brush : _brushes.fg)
802 brush = effects.brush(brush, _brushes.bg[0]);
805 _brushes.deco[0] = effects.brush(_brushes.deco[0], _brushes.bg[0]);
806 _brushes.deco[1] = effects.brush(_brushes.deco[1], _brushes.bg[0]);
807 _brushes.bg[0] = effects.brush(_brushes.bg[0]);
808 _brushes.bg[1] = effects.brush(_brushes.bg[1]);
812 _brushes.bg[2] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[2].color());
813 _brushes.bg[3] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[3].color());
814 _brushes.bg[4] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[4].color());
815 _brushes.bg[5] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[5].color());
816 _brushes.bg[6] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[6].color());
817 _brushes.bg[7] = ColorTools::tint(_brushes.bg[0].color(), _brushes.fg[7].color());
825 return _brushes.bg[1];
827 return _brushes.bg[2];
829 return _brushes.bg[3];
831 return _brushes.bg[4];
833 return _brushes.bg[5];
835 return _brushes.bg[6];
837 return _brushes.bg[7];
839 return _brushes.bg[0];
848 return _brushes.fg[1];
850 return _brushes.fg[2];
852 return _brushes.fg[3];
854 return _brushes.fg[4];
856 return _brushes.fg[5];
858 return _brushes.fg[6];
860 return _brushes.fg[7];
862 return _brushes.fg[0];
871 return _brushes.deco[1];
873 return _brushes.deco[0];
877qreal SchemeManagerPrivate::contrast()
const
888SchemeManager::~SchemeManager()
908 d =
new SchemeManagerPrivate(config, state,
"Colors:Window", defaultWindowColors);
911 d =
new SchemeManagerPrivate(config, state,
"Colors:Button", defaultButtonColors);
917 bool inactiveSelectionEffect = group.
readEntry(
"ChangeSelectionColor", group.
readEntry(
"Enable",
true));
922 d =
new SchemeManagerPrivate(config, state,
"Colors:Selection", defaultSelectionColors);
926 d =
new SchemeManagerPrivate(config, state,
"Colors:Window", defaultWindowColors,
932 d =
new SchemeManagerPrivate(config, state,
"Colors:Window", defaultWindowColors);
937 d =
new SchemeManagerPrivate(config, state,
"Colors:Tooltip", defaultTooltipColors);
940 d =
new SchemeManagerPrivate(config, state,
"Colors:Complementary", defaultComplementaryColors);
943 d =
new SchemeManagerPrivate(config, state,
"Colors:View", defaultViewColors);
968 return d->background(role);
973 return d->foreground(role);
978 return d->decoration(role);
997 qreal y = ColorTools::luma(color);
1006 return ColorTools::shade(color, 0.05 + 0.95 *
contrast, chromaAdjust);
1008 return ColorTools::shade(color, 0.01 + 0.20 *
contrast, chromaAdjust);
1010 return ColorTools::shade(color, 0.02 + 0.40 *
contrast, chromaAdjust);
1012 return ColorTools::shade(color, 0.03 + 0.60 *
contrast, chromaAdjust);
1022 return ColorTools::shade(color, -0.02 - 0.20 *
contrast, chromaAdjust);
1024 return ColorTools::shade(color, -0.06 - 0.60 *
contrast, chromaAdjust);
1026 return ColorTools::shade(color, -0.10 - 0.90 *
contrast, chromaAdjust);
1028 return ColorTools::shade(color, -0.04 - 0.40 *
contrast, chromaAdjust);
1033 qreal lightAmount = (0.05 + y * 0.55) * (0.25 +
contrast * 0.75);
1034 qreal darkAmount = (- y) * (0.55 +
contrast * 0.35);
1039 return ColorTools::shade(color, lightAmount, chromaAdjust);
1041 return ColorTools::shade(color, (0.15 + 0.35 * yi) * lightAmount, chromaAdjust);
1043 return ColorTools::shade(color, (0.35 + 0.15 * y) * darkAmount, chromaAdjust);
1045 return ColorTools::shade(color, darkAmount, chromaAdjust);
1047 return ColorTools::darken(ColorTools::shade(color, darkAmount, chromaAdjust), 0.5 + 0.3 * y);
1052 ColorSet set, KSharedConfigPtr config)
1060 ColorSet set, KSharedConfigPtr config)
1081 for (
auto &state : states)
QString readEntry(const char *key, const char *aDefault=nullptr) const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
ColorSet
This enumeration describes the color set for which a color is being selected.
@ Selection
Selected items in views.
@ Complementary
Complementary areas.
@ View
Views; for example, frames, input fields, etc.
@ Button
Buttons and button-like controls.
@ Window
Non-editable window elements; for example, menus.
QBrush background(BackgroundRole=NormalBackground) const
Retrieve the requested background brush.
static void adjustBackground(QPalette &, BackgroundRole newRole=NormalBackground, QPalette::ColorRole color=QPalette::Base, ColorSet set=View, KSharedConfigPtr=KSharedConfigPtr())
Adjust a QPalette by replacing the specified QPalette::ColorRole with the requested background color ...
static qreal contrastF(const KSharedConfigPtr &config=KSharedConfigPtr())
Returns the contrast for borders as a floating point value.
BackgroundRole
This enumeration describes the background color being selected from the given set.
@ LinkBackground
Fourth color; corresponds to (unvisited) links.
@ PositiveBackground
Eigth color; for example, success messages, trusted content.
@ AlternateBackground
Alternate background; for example, for use in lists.
@ ActiveBackground
Third color; for example, items which are new, active, requesting attention, etc.
@ VisitedBackground
Fifth color; corresponds to visited links.
@ NegativeBackground
Sixth color; for example, errors, untrusted content, etc.
@ NeutralBackground
Seventh color; for example, warnings, secure/encrypted content.
ForegroundRole
This enumeration describes the foreground color being selected from the given set.
@ InactiveText
Second color; for example, comments, items which are old, inactive or disabled.
@ LinkText
Fourth color; use for (unvisited) links.
@ VisitedText
Fifth color; used for (visited) links.
@ ActiveText
Third color; for example items which are new, active, requesting attention, etc.
@ NegativeText
Sixth color; for example, errors, untrusted content, deletions, etc.
@ NeutralText
Seventh color; for example, warnings, secure/encrypted content.
@ PositiveText
Eigth color; for example, additions, success messages, trusted content.
SchemeManager & operator=(const SchemeManager &)
Standard assignment operator.
static void adjustForeground(QPalette &, ForegroundRole newRole=NormalText, QPalette::ColorRole color=QPalette::Text, ColorSet set=View, KSharedConfigPtr=KSharedConfigPtr())
Adjust a QPalette by replacing the specified QPalette::ColorRole with the requested foreground color ...
static int contrast()
Returns the contrast for borders.
DecorationRole
This enumeration describes the decoration color being selected from the given set.
@ FocusColor
Color used to draw decorations for items which have input focus.
static QPalette createApplicationPalette(const KSharedConfigPtr &config)
Used to obtain the QPalette that will be used to set the application palette from KDE Platform theme.
QColor shade(ShadeRole) const
Retrieve the requested shade color, using SchemeManager::background(SchemeManager::NormalBackground) ...
QBrush decoration(DecorationRole) const
Retrieve the requested decoration brush.
ShadeRole
This enumeration describes the color shade being selected from the given set.
@ DarkShade
The dark color is in between mid() and shadow().
@ MidlightShade
The midlight color is in between base() and light().
@ LightShade
The light color is lighter than dark() or shadow() and contrasts with the base color.
@ ShadowShade
The shadow color is darker than light() or midlight() and contrasts the base color.
@ MidShade
The mid color is in between base() and dark().
QBrush foreground(ForegroundRole=NormalText) const
Retrieve the requested foreground brush.
SchemeManager(const SchemeManager &)
Construct a copy of another SchemeManager.
KGUIADDONS_EXPORT QColor tint(const QColor &base, const QColor &color, qreal amount=0.3)
const QColor & color() const const
float alphaF() const const
float blueF() const const
QColor fromRgbF(float r, float g, float b, float a)
float greenF() const const
void setBrush(ColorGroup group, ColorRole role, const QBrush &brush)
void setColor(ColorGroup group, ColorRole role, const QColor &color)
bool isEmpty() const const