diff --git a/src/kcolorscheme.cpp b/src/kcolorscheme.cpp index a5a53a9..5be7efd 100644 --- a/src/kcolorscheme.cpp +++ b/src/kcolorscheme.cpp @@ -1,745 +1,754 @@ /* This file is part of the KDE project * Copyright (C) 2007 Matthew Woehlke * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kcolorscheme.h" #include #include #include #include #include #include #include #include //BEGIN StateEffects class StateEffects { public: explicit StateEffects(QPalette::ColorGroup state, const KSharedConfigPtr &); ~StateEffects() {} //{ delete chain; } not needed yet QBrush brush(const QBrush &background) const; QBrush brush(const QBrush &foreground, const QBrush &background) const; private: - enum Effects { - // Effects - Intensity = 0, - Color = 1, - Contrast = 2, - // Intensity - IntensityNoEffect = 0, - IntensityShade = 1, - IntensityDarken = 2, - IntensityLighten = 3, - // Color - ColorNoEffect = 0, - ColorDesaturate = 1, - ColorFade = 2, - ColorTint = 3, - // Contrast - ContrastNoEffect = 0, - ContrastFade = 1, - ContrastTint = 2 + enum EffectTypes { + Intensity, + Color, + Contrast, + NEffectTypes + }; + + enum IntensityEffects { + IntensityNoEffect, + IntensityShade, + IntensityDarken, + IntensityLighten, + NIntensityEffects + }; + + enum ColorEffects { + ColorNoEffect, + ColorDesaturate, + ColorFade, + ColorTint, + NColorEffects + }; + + enum ContrastEffects { + ContrastNoEffect, + ContrastFade, + ContrastTint, + NContrastEffects }; int _effects[3]; double _amount[3]; QColor _color; // StateEffects *_chain; not needed yet }; StateEffects::StateEffects(QPalette::ColorGroup state, const KSharedConfigPtr &config) : _color(0, 0, 0, 0) //, _chain(0) not needed yet { QString group; if (state == QPalette::Disabled) { group = QStringLiteral("ColorEffects:Disabled"); } else if (state == QPalette::Inactive) { group = QStringLiteral("ColorEffects:Inactive"); } _effects[0] = 0; _effects[1] = 0; _effects[2] = 0; // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp if (! group.isEmpty()) { KConfigGroup cfg(config, group); const bool enabledByDefault = (state == QPalette::Disabled); if (cfg.readEntry("Enable", enabledByDefault)) { _effects[Intensity] = cfg.readEntry("IntensityEffect", (int)(state == QPalette::Disabled ? IntensityDarken : IntensityNoEffect)); _effects[Color] = cfg.readEntry("ColorEffect", (int)(state == QPalette::Disabled ? ColorNoEffect : ColorDesaturate)); _effects[Contrast] = cfg.readEntry("ContrastEffect", (int)(state == QPalette::Disabled ? ContrastFade : ContrastTint)); _amount[Intensity] = cfg.readEntry("IntensityAmount", state == QPalette::Disabled ? 0.10 : 0.0); _amount[Color] = cfg.readEntry("ColorAmount", state == QPalette::Disabled ? 0.0 : -0.9); _amount[Contrast] = cfg.readEntry("ContrastAmount", state == QPalette::Disabled ? 0.65 : 0.25); if (_effects[Color] > ColorNoEffect) { _color = cfg.readEntry("Color", state == QPalette::Disabled ? QColor(56, 56, 56) : QColor(112, 111, 110)); } } } } QBrush StateEffects::brush(const QBrush &background) const { QColor color = background.color(); // TODO - actually work on brushes switch (_effects[Intensity]) { case IntensityShade: color = KColorUtils::shade(color, _amount[Intensity]); break; case IntensityDarken: color = KColorUtils::darken(color, _amount[Intensity]); break; case IntensityLighten: color = KColorUtils::lighten(color, _amount[Intensity]); break; } switch (_effects[Color]) { case ColorDesaturate: color = KColorUtils::darken(color, 0.0, 1.0 - _amount[Color]); break; case ColorFade: color = KColorUtils::mix(color, _color, _amount[Color]); break; case ColorTint: color = KColorUtils::tint(color, _color, _amount[Color]); break; } return QBrush(color); } QBrush StateEffects::brush(const QBrush &foreground, const QBrush &background) const { QColor color = foreground.color(); // TODO - actually work on brushes QColor bg = background.color(); // Apply the foreground effects switch (_effects[Contrast]) { case ContrastFade: color = KColorUtils::mix(color, bg, _amount[Contrast]); break; case ContrastTint: color = KColorUtils::tint(color, bg, _amount[Contrast]); break; } // Now apply global effects return brush(color); } //END StateEffects //BEGIN default colors struct SetDefaultColors { int NormalBackground[3]; int AlternateBackground[3]; int NormalText[3]; int InactiveText[3]; int ActiveText[3]; int LinkText[3]; int VisitedText[3]; int NegativeText[3]; int NeutralText[3]; int PositiveText[3]; }; struct DecoDefaultColors { int Hover[3]; int Focus[3]; }; // these numbers come from the Breeze color scheme ([breeze]/colors/Breeze.colors) static const SetDefaultColors defaultViewColors = { { 252, 252, 252 }, // Background { 239, 240, 241 }, // Alternate { 35, 38, 39 }, // Normal { 127, 140, 141 }, // Inactive { 61, 174, 233 }, // Active { 41, 128, 185 }, // Link { 127, 140, 141 }, // Visited { 218, 68, 83 }, // Negative { 246, 116, 0 }, // Neutral { 39, 174, 96 } // Positive }; static const SetDefaultColors defaultWindowColors = { { 239, 240, 241 }, // Background { 189, 195, 199 }, // Alternate { 35, 38, 39 }, // Normal { 127, 140, 141 }, // Inactive { 61, 174, 233 }, // Active { 41, 128, 185 }, // Link { 127, 140, 141 }, // Visited { 218, 68, 83 }, // Negative { 246, 116, 0 }, // Neutral { 39, 174, 96 } // Positive }; static const SetDefaultColors defaultButtonColors = { { 239, 240, 241 }, // Background { 189, 195, 199 }, // Alternate { 35, 38, 39 }, // Normal { 127, 140, 141 }, // Inactive { 61, 174, 233 }, // Active { 41, 128, 185 }, // Link { 127, 140, 141 }, // Visited { 218, 68, 83 }, // Negative { 246, 116, 0 }, // Neutral { 39, 174, 96 } // Positive }; static const SetDefaultColors defaultSelectionColors = { { 61, 174, 233 }, // Background { 29, 153, 243 }, // Alternate { 252, 252, 252 }, // Normal { 239, 240, 241 }, // Inactive { 252, 252, 252 }, // Active { 253, 188, 75 }, // Link { 189, 195, 199 }, // Visited { 218, 68, 83 }, // Negative { 246, 116, 0 }, // Neutral { 39, 174, 96 } // Positive }; static const SetDefaultColors defaultTooltipColors = { { 35, 38, 39 }, // Background { 77, 77, 77 }, // Alternate { 252, 252, 252 }, // Normal { 189, 195, 199 }, // Inactive { 61, 174, 233 }, // Active { 41, 128, 185 }, // Link { 127, 140, 141 }, // Visited { 218, 68, 83 }, // Negative { 246, 116, 0 }, // Neutral { 39, 174, 96 } // Positive }; static const SetDefaultColors defaultComplementaryColors = { { 49, 54, 59 }, // Background { 59, 64, 69 }, // Alternate { 239, 240, 241 }, // Normal { 175, 176, 179 }, // Inactive { 147, 206, 233 }, // Active { 61, 174, 230 }, // Link { 61, 174, 230 }, // Visited { 231, 76, 60 }, // Negative { 253, 188, 75 }, // Neutral { 46, 174, 230 } // Positive }; static const DecoDefaultColors defaultDecorationColors = { { 147, 206, 233 }, // Hover { 61, 174, 233 }, // Focus }; //END default colors KSharedConfigPtr defaultConfig() { // cache the value we'll return, since usually it's going to be the same value static thread_local KSharedConfigPtr config; // Read from the application's color scheme file (as set by KColorSchemeManager). // If unset, this is equivalent to openConfig() and the system scheme is used. const auto colorSchemePath = qApp->property("KDE_COLOR_SCHEME_PATH").toString(); if (!config || config->name() != colorSchemePath) { config = KSharedConfig::openConfig(colorSchemePath); } return config; } //BEGIN KColorSchemePrivate class KColorSchemePrivate : public QSharedData { public: explicit KColorSchemePrivate(const KSharedConfigPtr &, QPalette::ColorGroup, const char *, const SetDefaultColors &); explicit KColorSchemePrivate(const KSharedConfigPtr &, QPalette::ColorGroup, const char *, const SetDefaultColors &, const QBrush &); ~KColorSchemePrivate() {} QBrush background(KColorScheme::BackgroundRole) const; QBrush foreground(KColorScheme::ForegroundRole) const; QBrush decoration(KColorScheme::DecorationRole) const; qreal contrast() const; private: struct { QBrush fg[8], bg[8], deco[2]; } _brushes; qreal _contrast; void init(const KSharedConfigPtr &, QPalette::ColorGroup, const char *, const SetDefaultColors &); }; #define DEFAULT(c) QColor( c[0], c[1], c[2] ) #define SET_DEFAULT(a) DEFAULT( defaults.a ) #define DECO_DEFAULT(a) DEFAULT( defaultDecorationColors.a ) KColorSchemePrivate::KColorSchemePrivate(const KSharedConfigPtr &config, QPalette::ColorGroup state, const char *group, const SetDefaultColors &defaults) { KConfigGroup cfg(config, group); _contrast = KColorScheme::contrastF(config); // loaded-from-config colors (no adjustment) _brushes.bg[0] = cfg.readEntry("BackgroundNormal", SET_DEFAULT(NormalBackground)); _brushes.bg[1] = cfg.readEntry("BackgroundAlternate", SET_DEFAULT(AlternateBackground)); // the rest init(config, state, group, defaults); } KColorSchemePrivate::KColorSchemePrivate(const KSharedConfigPtr &config, QPalette::ColorGroup state, const char *group, const SetDefaultColors &defaults, const QBrush &tint) { KConfigGroup cfg(config, group); _contrast = KColorScheme::contrastF(config); // loaded-from-config colors _brushes.bg[0] = cfg.readEntry("BackgroundNormal", SET_DEFAULT(NormalBackground)); _brushes.bg[1] = cfg.readEntry("BackgroundAlternate", SET_DEFAULT(AlternateBackground)); // adjustment _brushes.bg[0] = KColorUtils::tint(_brushes.bg[0].color(), tint.color(), 0.4); _brushes.bg[1] = KColorUtils::tint(_brushes.bg[1].color(), tint.color(), 0.4); // the rest init(config, state, group, defaults); } void KColorSchemePrivate::init(const KSharedConfigPtr &config, QPalette::ColorGroup state, const char *group, const SetDefaultColors &defaults) { KConfigGroup cfg(config, group); // loaded-from-config colors _brushes.fg[0] = cfg.readEntry("ForegroundNormal", SET_DEFAULT(NormalText)); _brushes.fg[1] = cfg.readEntry("ForegroundInactive", SET_DEFAULT(InactiveText)); _brushes.fg[2] = cfg.readEntry("ForegroundActive", SET_DEFAULT(ActiveText)); _brushes.fg[3] = cfg.readEntry("ForegroundLink", SET_DEFAULT(LinkText)); _brushes.fg[4] = cfg.readEntry("ForegroundVisited", SET_DEFAULT(VisitedText)); _brushes.fg[5] = cfg.readEntry("ForegroundNegative", SET_DEFAULT(NegativeText)); _brushes.fg[6] = cfg.readEntry("ForegroundNeutral", SET_DEFAULT(NeutralText)); _brushes.fg[7] = cfg.readEntry("ForegroundPositive", SET_DEFAULT(PositiveText)); _brushes.deco[0] = cfg.readEntry("DecorationHover", DECO_DEFAULT(Hover)); _brushes.deco[1] = cfg.readEntry("DecorationFocus", DECO_DEFAULT(Focus)); // apply state adjustments if (state != QPalette::Active) { StateEffects effects(state, config); for (int i = 0; i < 8; i++) { _brushes.fg[i] = effects.brush(_brushes.fg[i], _brushes.bg[0]); } _brushes.deco[0] = effects.brush(_brushes.deco[0], _brushes.bg[0]); _brushes.deco[1] = effects.brush(_brushes.deco[1], _brushes.bg[0]); _brushes.bg[0] = effects.brush(_brushes.bg[0]); _brushes.bg[1] = effects.brush(_brushes.bg[1]); } // calculated backgrounds _brushes.bg[2] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[2].color()); _brushes.bg[3] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[3].color()); _brushes.bg[4] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[4].color()); _brushes.bg[5] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[5].color()); _brushes.bg[6] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[6].color()); _brushes.bg[7] = KColorUtils::tint(_brushes.bg[0].color(), _brushes.fg[7].color()); } QBrush KColorSchemePrivate::background(KColorScheme::BackgroundRole role) const { switch (role) { case KColorScheme::AlternateBackground: return _brushes.bg[1]; case KColorScheme::ActiveBackground: return _brushes.bg[2]; case KColorScheme::LinkBackground: return _brushes.bg[3]; case KColorScheme::VisitedBackground: return _brushes.bg[4]; case KColorScheme::NegativeBackground: return _brushes.bg[5]; case KColorScheme::NeutralBackground: return _brushes.bg[6]; case KColorScheme::PositiveBackground: return _brushes.bg[7]; default: return _brushes.bg[0]; } } QBrush KColorSchemePrivate::foreground(KColorScheme::ForegroundRole role) const { switch (role) { case KColorScheme::InactiveText: return _brushes.fg[1]; case KColorScheme::ActiveText: return _brushes.fg[2]; case KColorScheme::LinkText: return _brushes.fg[3]; case KColorScheme::VisitedText: return _brushes.fg[4]; case KColorScheme::NegativeText: return _brushes.fg[5]; case KColorScheme::NeutralText: return _brushes.fg[6]; case KColorScheme::PositiveText: return _brushes.fg[7]; default: return _brushes.fg[0]; } } QBrush KColorSchemePrivate::decoration(KColorScheme::DecorationRole role) const { switch (role) { case KColorScheme::FocusColor: return _brushes.deco[1]; default: return _brushes.deco[0]; } } qreal KColorSchemePrivate::contrast() const { return _contrast; } //END KColorSchemePrivate //BEGIN KColorScheme KColorScheme::KColorScheme(const KColorScheme &other) : d(other.d) { } KColorScheme &KColorScheme::operator=(const KColorScheme &other) { d = other.d; return *this; } KColorScheme::~KColorScheme() { } KColorScheme::KColorScheme(QPalette::ColorGroup state, ColorSet set, KSharedConfigPtr config) { if (!config) { config = defaultConfig(); } switch (set) { case Window: d = new KColorSchemePrivate(config, state, "Colors:Window", defaultWindowColors); break; case Button: d = new KColorSchemePrivate(config, state, "Colors:Button", defaultButtonColors); break; case Selection: { KConfigGroup group(config, "ColorEffects:Inactive"); // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp bool inactiveSelectionEffect = group.readEntry("ChangeSelectionColor", group.readEntry("Enable", true)); // if enabled, inactiver/disabled uses Window colors instead, ala gtk // ...except tinted with the Selection:NormalBackground color so it looks more like selection if (state == QPalette::Active || (state == QPalette::Inactive && !inactiveSelectionEffect)) { d = new KColorSchemePrivate(config, state, "Colors:Selection", defaultSelectionColors); } else if (state == QPalette::Inactive) d = new KColorSchemePrivate(config, state, "Colors:Window", defaultWindowColors, KColorScheme(QPalette::Active, Selection, config).background()); else { // disabled (...and still want this branch when inactive+disabled exists) d = new KColorSchemePrivate(config, state, "Colors:Window", defaultWindowColors); } } break; case Tooltip: d = new KColorSchemePrivate(config, state, "Colors:Tooltip", defaultTooltipColors); break; case Complementary: d = new KColorSchemePrivate(config, state, "Colors:Complementary", defaultComplementaryColors); break; default: d = new KColorSchemePrivate(config, state, "Colors:View", defaultViewColors); } } // static int KColorScheme::contrast() { KConfigGroup g(KSharedConfig::openConfig(), "KDE"); return g.readEntry("contrast", 7); } // static qreal KColorScheme::contrastF(const KSharedConfigPtr &config) { if (config) { KConfigGroup g(config, "KDE"); return 0.1 * g.readEntry("contrast", 7); } return 0.1 * (qreal)contrast(); } QBrush KColorScheme::background(BackgroundRole role) const { return d->background(role); } QBrush KColorScheme::foreground(ForegroundRole role) const { return d->foreground(role); } QBrush KColorScheme::decoration(DecorationRole role) const { return d->decoration(role); } QColor KColorScheme::shade(ShadeRole role) const { return shade(background().color(), role, d->contrast()); } QColor KColorScheme::shade(const QColor &color, ShadeRole role) { return shade(color, role, KColorScheme::contrastF()); } QColor KColorScheme::shade(const QColor &color, ShadeRole role, qreal contrast, qreal chromaAdjust) { // nan -> 1.0 contrast = (1.0 > contrast ? (-1.0 < contrast ? contrast : -1.0) : 1.0); qreal y = KColorUtils::luma(color), yi = 1.0 - y; // handle very dark colors (base, mid, dark, shadow == midlight, light) if (y < 0.006) { switch (role) { case KColorScheme::LightShade: return KColorUtils::shade(color, 0.05 + 0.95 * contrast, chromaAdjust); case KColorScheme::MidShade: return KColorUtils::shade(color, 0.01 + 0.20 * contrast, chromaAdjust); case KColorScheme::DarkShade: return KColorUtils::shade(color, 0.02 + 0.40 * contrast, chromaAdjust); default: return KColorUtils::shade(color, 0.03 + 0.60 * contrast, chromaAdjust); } } // handle very light colors (base, midlight, light == mid, dark, shadow) if (y > 0.93) { switch (role) { case KColorScheme::MidlightShade: return KColorUtils::shade(color, -0.02 - 0.20 * contrast, chromaAdjust); case KColorScheme::DarkShade: return KColorUtils::shade(color, -0.06 - 0.60 * contrast, chromaAdjust); case KColorScheme::ShadowShade: return KColorUtils::shade(color, -0.10 - 0.90 * contrast, chromaAdjust); default: return KColorUtils::shade(color, -0.04 - 0.40 * contrast, chromaAdjust); } } // handle everything else qreal lightAmount = (0.05 + y * 0.55) * (0.25 + contrast * 0.75); qreal darkAmount = (- y) * (0.55 + contrast * 0.35); switch (role) { case KColorScheme::LightShade: return KColorUtils::shade(color, lightAmount, chromaAdjust); case KColorScheme::MidlightShade: return KColorUtils::shade(color, (0.15 + 0.35 * yi) * lightAmount, chromaAdjust); case KColorScheme::MidShade: return KColorUtils::shade(color, (0.35 + 0.15 * y) * darkAmount, chromaAdjust); case KColorScheme::DarkShade: return KColorUtils::shade(color, darkAmount, chromaAdjust); default: return KColorUtils::darken(KColorUtils::shade(color, darkAmount, chromaAdjust), 0.5 + 0.3 * y); } } void KColorScheme::adjustBackground(QPalette &palette, BackgroundRole newRole, QPalette::ColorRole color, ColorSet set, KSharedConfigPtr config) { palette.setBrush(QPalette::Active, color, KColorScheme(QPalette::Active, set, config).background(newRole)); palette.setBrush(QPalette::Inactive, color, KColorScheme(QPalette::Inactive, set, config).background(newRole)); palette.setBrush(QPalette::Disabled, color, KColorScheme(QPalette::Disabled, set, config).background(newRole)); } void KColorScheme::adjustForeground(QPalette &palette, ForegroundRole newRole, QPalette::ColorRole color, ColorSet set, KSharedConfigPtr config) { palette.setBrush(QPalette::Active, color, KColorScheme(QPalette::Active, set, config).foreground(newRole)); palette.setBrush(QPalette::Inactive, color, KColorScheme(QPalette::Inactive, set, config).foreground(newRole)); palette.setBrush(QPalette::Disabled, color, KColorScheme(QPalette::Disabled, set, config).foreground(newRole)); } QPalette KColorScheme::createApplicationPalette(const KSharedConfigPtr &config) { QPalette palette; static const QPalette::ColorGroup states[3] = { QPalette::Active, QPalette::Inactive, QPalette::Disabled }; // TT thinks tooltips shouldn't use active, so we use our active colors for all states KColorScheme schemeTooltip(QPalette::Active, KColorScheme::Tooltip, config); for (int i = 0; i < 3; i++) { QPalette::ColorGroup state = states[i]; KColorScheme schemeView(state, KColorScheme::View, config); KColorScheme schemeWindow(state, KColorScheme::Window, config); KColorScheme schemeButton(state, KColorScheme::Button, config); KColorScheme schemeSelection(state, KColorScheme::Selection, config); palette.setBrush(state, QPalette::WindowText, schemeWindow.foreground()); palette.setBrush(state, QPalette::Window, schemeWindow.background()); palette.setBrush(state, QPalette::Base, schemeView.background()); palette.setBrush(state, QPalette::Text, schemeView.foreground()); palette.setBrush(state, QPalette::Button, schemeButton.background()); palette.setBrush(state, QPalette::ButtonText, schemeButton.foreground()); palette.setBrush(state, QPalette::Highlight, schemeSelection.background()); palette.setBrush(state, QPalette::HighlightedText, schemeSelection.foreground()); palette.setBrush(state, QPalette::ToolTipBase, schemeTooltip.background()); palette.setBrush(state, QPalette::ToolTipText, schemeTooltip.foreground()); palette.setColor(state, QPalette::Light, schemeWindow.shade(KColorScheme::LightShade)); palette.setColor(state, QPalette::Midlight, schemeWindow.shade(KColorScheme::MidlightShade)); palette.setColor(state, QPalette::Mid, schemeWindow.shade(KColorScheme::MidShade)); palette.setColor(state, QPalette::Dark, schemeWindow.shade(KColorScheme::DarkShade)); palette.setColor(state, QPalette::Shadow, schemeWindow.shade(KColorScheme::ShadowShade)); palette.setBrush(state, QPalette::AlternateBase, schemeView.background(KColorScheme::AlternateBackground)); palette.setBrush(state, QPalette::Link, schemeView.foreground(KColorScheme::LinkText)); palette.setBrush(state, QPalette::LinkVisited, schemeView.foreground(KColorScheme::VisitedText)); } return palette; } //END KColorScheme //BEGIN KStatefulBrush class KStatefulBrushPrivate : public QBrush // for now, just be a QBrush { public: KStatefulBrushPrivate() : QBrush() {} KStatefulBrushPrivate(const QBrush &brush) : QBrush(brush) {} // not explicit }; KStatefulBrush::KStatefulBrush() { d = new KStatefulBrushPrivate[3]; } KStatefulBrush::KStatefulBrush(KColorScheme::ColorSet set, KColorScheme::ForegroundRole role, KSharedConfigPtr config) { d = new KStatefulBrushPrivate[3]; d[0] = KColorScheme(QPalette::Active, set, config).foreground(role); d[1] = KColorScheme(QPalette::Disabled, set, config).foreground(role); d[2] = KColorScheme(QPalette::Inactive, set, config).foreground(role); } KStatefulBrush::KStatefulBrush(KColorScheme::ColorSet set, KColorScheme::BackgroundRole role, KSharedConfigPtr config) { d = new KStatefulBrushPrivate[3]; d[0] = KColorScheme(QPalette::Active, set, config).background(role); d[1] = KColorScheme(QPalette::Disabled, set, config).background(role); d[2] = KColorScheme(QPalette::Inactive, set, config).background(role); } KStatefulBrush::KStatefulBrush(KColorScheme::ColorSet set, KColorScheme::DecorationRole role, KSharedConfigPtr config) { d = new KStatefulBrushPrivate[3]; d[0] = KColorScheme(QPalette::Active, set, config).decoration(role); d[1] = KColorScheme(QPalette::Disabled, set, config).decoration(role); d[2] = KColorScheme(QPalette::Inactive, set, config).decoration(role); } KStatefulBrush::KStatefulBrush(const QBrush &brush, KSharedConfigPtr config) { if (!config) { config = defaultConfig(); } d = new KStatefulBrushPrivate[3]; d[0] = brush; d[1] = StateEffects(QPalette::Disabled, config).brush(brush); d[2] = StateEffects(QPalette::Inactive, config).brush(brush); } KStatefulBrush::KStatefulBrush(const QBrush &brush, const QBrush &background, KSharedConfigPtr config) { if (!config) { config = defaultConfig(); } d = new KStatefulBrushPrivate[3]; d[0] = brush; d[1] = StateEffects(QPalette::Disabled, config).brush(brush, background); d[2] = StateEffects(QPalette::Inactive, config).brush(brush, background); } KStatefulBrush::KStatefulBrush(const KStatefulBrush &other) { d = new KStatefulBrushPrivate[3]; d[0] = other.d[0]; d[1] = other.d[1]; d[2] = other.d[2]; } KStatefulBrush::~KStatefulBrush() { delete[] d; } KStatefulBrush &KStatefulBrush::operator=(const KStatefulBrush &other) { d[0] = other.d[0]; d[1] = other.d[1]; d[2] = other.d[2]; return *this; } QBrush KStatefulBrush::brush(QPalette::ColorGroup state) const { switch (state) { case QPalette::Inactive: return d[2]; case QPalette::Disabled: return d[1]; default: return d[0]; } } QBrush KStatefulBrush::brush(const QPalette &pal) const { return brush(pal.currentColorGroup()); } QBrush KStatefulBrush::brush(const QWidget *widget) const { if (widget) { return brush(widget->palette()); } else { return QBrush(); } } //END KStatefulBrush diff --git a/src/kcolorscheme.h b/src/kcolorscheme.h index 808e614..fac8054 100644 --- a/src/kcolorscheme.h +++ b/src/kcolorscheme.h @@ -1,582 +1,607 @@ /* This file is part of the KDE project * Copyright (C) 2007 Matthew Woehlke * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KCOLORSCHEME_H #define KCOLORSCHEME_H #include #include #include #include class QColor; class QBrush; class KColorSchemePrivate; /** * @class KColorScheme kcolorscheme.h KColorScheme * * A set of methods used to work with colors. * * KColorScheme currently provides access to the system color palette that the * user has selected (in the future, it is expected to do more). It greatly * expands on QPalette by providing five distinct "sets" with several color * choices each, covering background, foreground, and decoration colors. * * A KColorScheme instance represents colors corresponding to a "set", where a * set consists of those colors used to draw a particular type of element, such * as a menu, button, view, selected text, or tooltip. Each set has a distinct * set of colors, so you should always use the correct set for drawing and * never assume that a particular foreground for one set is the same as the * foreground for any other set. Individual colors may be quickly referenced by * creating an anonymous instance and invoking a lookup member. * * @note * The color palettes for the various states of a widget (active, inactive, * disabled) may be wildly different. Therefore, it is important to take the * state into account. This is why the KColorScheme constructor requires a * QPalette::ColorGroup as an argument. * * To facilitate working with potentially-varying states, two convenience API's * are provided. These are KColorScheme::adjustBackground and its sister * KColorScheme::adjustForeground, and the helper class ::KStatefulBrush. * * @see KColorScheme::ColorSet, KColorScheme::ForegroundRole, * KColorScheme::BackgroundRole, KColorScheme::DecorationRole, * KColorScheme::ShadeRole */ class KCONFIGWIDGETS_EXPORT KColorScheme { public: /** * This enumeration describes the color set for which a color is being * selected. * * Color sets define a color "environment", suitable for drawing all parts * of a given region. Colors from different sets should not be combined. */ enum ColorSet { /** * Views; for example, frames, input fields, etc. * * If it contains things that can be selected, it is probably a View. */ View, /** * Non-editable window elements; for example, menus. * * If it isn't a Button, View, or Tooltip, it is probably a Window. */ Window, /** * Buttons and button-like controls. * * In addition to buttons, "button-like" controls such as non-editable * dropdowns, scrollbar sliders, slider handles, etc. should also use * this role. */ Button, /** * Selected items in views. * * Note that unfocused or disabled selections should use the Window * role. This makes it more obvious to the user that the view * containing the selection does not have input focus. */ Selection, /** * Tooltips. * * The tooltip set can often be substituted for the view * set when editing is not possible, but the Window set is deemed * inappropriate. "What's This" help is an excellent example, another * might be pop-up notifications (depending on taste). */ Tooltip, /** * Complementary areas. * * Some applications want some areas to have a different color scheme. * Usually dark areas over a light theme. For instance the fullscreen UI * of a picture viewer, or the logout/lock screen of the plasma workspace * ask for a dark color scheme even on light themes. * @since 5.19 */ - Complementary + Complementary, + /** + * Number of color sets. + * @since 5.65 + */ + NColorSets }; /** * This enumeration describes the background color being selected from the * given set. * * Background colors are suitable for drawing under text, and should never * be used to draw text. In combination with one of the overloads of * KColorScheme::shade, they may be used to generate colors for drawing * frames, bevels, and similar decorations. */ enum BackgroundRole { /** * Normal background. */ - NormalBackground = 0, + NormalBackground, /** * Alternate background; for example, for use in lists. * * This color may be the same as BackgroundNormal, especially in sets * other than View and Window. */ - AlternateBackground = 1, + AlternateBackground, /** * Third color; for example, items which are new, active, requesting * attention, etc. * * Alerting the user that a certain field must be filled out would be a * good usage (although NegativeBackground could be used to the same * effect, depending on what you are trying to achieve). Unlike * ActiveText, this should not be used for mouseover effects. */ - ActiveBackground = 2, + ActiveBackground, /** * Fourth color; corresponds to (unvisited) links. * * Exactly what this might be used for is somewhat harder to qualify; * it might be used for bookmarks, as a 'you can click here' indicator, * or to highlight recent content (i.e. in a most-recently-accessed * list). */ - LinkBackground = 3, + LinkBackground, /** * Fifth color; corresponds to visited links. * * This can also be used to indicate "not recent" content, especially * when a color is needed to denote content which is "old" or * "archival". */ - VisitedBackground = 4, + VisitedBackground, /** * Sixth color; for example, errors, untrusted content, etc. */ - NegativeBackground = 5, + NegativeBackground, /** * Seventh color; for example, warnings, secure/encrypted content. */ - NeutralBackground = 6, + NeutralBackground, /** * Eigth color; for example, success messages, trusted content. */ - PositiveBackground = 7 + PositiveBackground, + /** + * Number of background roles. + * @since 5.65 + */ + NBackgroundRoles }; /** * This enumeration describes the foreground color being selected from the * given set. * * Foreground colors are suitable for drawing text or glyphs (such as the * symbols on window decoration buttons, assuming a suitable background * brush is used), and should never be used to draw backgrounds. * * For window decorations, the following is suggested, but not set in * stone: * @li Maximize - PositiveText * @li Minimize - NeutralText * @li Close - NegativeText * @li WhatsThis - LinkText * @li Sticky - ActiveText */ enum ForegroundRole { /** * Normal foreground. */ - NormalText = 0, + NormalText, /** * Second color; for example, comments, items which are old, inactive * or disabled. Generally used for things that are meant to be "less * important". InactiveText is not the same role as NormalText in the * inactive state. */ - InactiveText = 1, + InactiveText, /** * Third color; for example items which are new, active, requesting * attention, etc. May be used as a hover color for clickable items. */ - ActiveText = 2, + ActiveText, /** * Fourth color; use for (unvisited) links. May also be used for other * clickable items or content that indicates relationships, items that * indicate somewhere the user can visit, etc. */ - LinkText = 3, + LinkText, /** * Fifth color; used for (visited) links. As with LinkText, may be used * for items that have already been "visited" or accessed. May also be * used to indicate "historical" (i.e. "old") items or information, * especially if InactiveText is being used in the same context to * express something different. */ - VisitedText = 4, + VisitedText, /** * Sixth color; for example, errors, untrusted content, deletions, * etc. */ - NegativeText = 5, + NegativeText, /** * Seventh color; for example, warnings, secure/encrypted content. */ - NeutralText = 6, + NeutralText, /** * Eigth color; for example, additions, success messages, trusted * content. */ - PositiveText = 7 + PositiveText, + /** + * Number of foreground roles. + * @since 5.65 + */ + NForegroundRoles }; /** * This enumeration describes the decoration color being selected from the * given set. * * Decoration colors are used to draw decorations (such as frames) for * special purposes. Like color shades, they are neither foreground nor * background colors. Text should not be painted over a decoration color, * and decoration colors should not be used to draw text. */ enum DecorationRole { /** * Color used to draw decorations for items which have input focus. */ FocusColor, /** * Color used to draw decorations for items which will be activated by * clicking. */ - HoverColor + HoverColor, + /** + * Number of decoration roles. + * @since 5.65 + */ + NDecorationRoles }; /** * This enumeration describes the color shade being selected from the given * set. * * Color shades are used to draw "3d" elements, such as frames and bevels. * They are neither foreground nor background colors. Text should not be * painted over a shade, and shades should not be used to draw text. */ enum ShadeRole { /** * The light color is lighter than dark() or shadow() and contrasts * with the base color. */ LightShade, /** * The midlight color is in between base() and light(). */ MidlightShade, /** * The mid color is in between base() and dark(). */ MidShade, /** * The dark color is in between mid() and shadow(). */ DarkShade, /** * The shadow color is darker than light() or midlight() and contrasts * the base color. */ - ShadowShade + ShadowShade, + /** + * Number of foreground roles. + * @since 5.65 + */ + NShadeRoles }; /** Construct a copy of another KColorScheme. */ KColorScheme(const KColorScheme &); /** Destructor */ virtual ~KColorScheme(); // TODO KF6: remove virtual /** Standard assignment operator */ KColorScheme &operator=(const KColorScheme &); /** * Construct a palette from given color set and state. Colors are taken * from the given KConfig. If null, the application's color scheme is used * (either the system default or one set by KColorSchemeManager). * * @note KColorScheme provides direct access to the color scheme for users * that deal directly with widget states. Unless you are a low-level user * or have a legitimate reason to only care about a fixed, limited number * of states (e.g. windows that cannot be inactive), consider using a * ::KStatefulBrush instead. */ explicit KColorScheme(QPalette::ColorGroup = QPalette::Normal, ColorSet = View, KSharedConfigPtr = KSharedConfigPtr()); /** * Retrieve the requested background brush. */ QBrush background(BackgroundRole = NormalBackground) const; /** * Retrieve the requested foreground brush. */ QBrush foreground(ForegroundRole = NormalText) const; /** * Retrieve the requested decoration brush. */ QBrush decoration(DecorationRole) const; /** * Retrieve the requested shade color, using * KColorScheme::background(KColorScheme::NormalBackground) * as the base color and the contrast setting from the KConfig used to * create this KColorScheme instance. * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). */ QColor shade(ShadeRole) const; /** * Returns the contrast for borders. * @return the contrast (between 0 for minimum and 10 for maximum * contrast) */ static int contrast(); /** * Returns the contrast for borders as a floating point value. * @param config pointer to the config from which to read the contrast * setting. If null, the application's color scheme will be used * (either the system default or one set by KColorSchemeManager). * @return the contrast (between 0.0 for minimum and 1.0 for maximum * contrast) */ static qreal contrastF(const KSharedConfigPtr &config = KSharedConfigPtr()); /** * Retrieve the requested shade color, using the specified color as the * base color and the application's contrast setting. * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). */ static QColor shade(const QColor &, ShadeRole); /** * Retrieve the requested shade color, using the specified color as the * base color and the specified contrast. * * @param contrast Amount roughly specifying the contrast by which to * adjust the base color, between -1.0 and 1.0 (values between 0.0 and 1.0 * correspond to the value from KColorScheme::contrastF) * @param chromaAdjust (optional) Amount by which to adjust the chroma of * the shade (1.0 means no adjustment) * * @note Shades are chosen such that all shades would contrast with the * base color. This means that if base is very dark, the 'dark' shades will * be lighter than the base color, with midlight() == shadow(). * Conversely, if the base color is very light, the 'light' shades will be * darker than the base color, with light() == mid(). * * @see KColorUtils::shade */ static QColor shade(const QColor &, ShadeRole, qreal contrast, qreal chromaAdjust = 0.0); /** * Adjust a QPalette by replacing the specified QPalette::ColorRole with * the requested background color for all states. Using this method is * safer than replacing individual states, as it insulates you against * changes in QPalette::ColorGroup. * * @note Although it is possible to replace a foreground color using this * method, it's bad usability to do so. Just say "no". */ 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 foreground color for all states. Using this method is * safer than replacing individual states, as it insulates you against * changes in QPalette::ColorGroup. * * @note Although it is possible to replace a background color using this * method, it's bad usability to do so. Just say "no". */ static void adjustForeground(QPalette &, ForegroundRole newRole = NormalText, QPalette::ColorRole color = QPalette::Text, ColorSet set = View, KSharedConfigPtr = KSharedConfigPtr()); /** * Used to obtain the QPalette that will be used to set the application * palette from KDE Platform theme. * * @param config KConfig from which to load the colors * * @returns the QPalette * * @since 5.0 */ static QPalette createApplicationPalette(const KSharedConfigPtr &config); private: QExplicitlySharedDataPointer d; }; Q_DECLARE_METATYPE(KColorScheme) /** * A container for a "state-aware" brush. * * KStatefulBrush provides an easy and safe way to store a color for use in a * user interface. It is "safe" both in that it will make it easy to deal with * widget states in a correct manner, and that it insulates you against changes * in QPalette::ColorGroup. * * Basically, a stateful brush is used to cache a particular "color" from the * KDE system palette (usually, one which does not live in QPalette). When you * are ready to draw using the brush, you use the current state to retrieve the * appropriate brush. * * Stateful brushes can also be used to apply state effects to arbitrary * brushes, for example when working with a application specific user-defined * color palette. * * @note As of Qt 4.3, QPalette::ColorGroup is missing a state for disabled * widgets in an inactive window. Hopefully Trolltech will fix this bug, at * which point KColorScheme and KStatefulBrush will be updated to recognize the * new state. Using KStatefulBrush will allow your application to inherit these * changes "for free", without even recompiling. */ class KCONFIGWIDGETS_EXPORT KStatefulBrush { public: /** * Construct a "default" stateful brush. For such an instance, all * overloads of KStatefulBrush::brush will return a default brush (i.e. * QBrush()). */ explicit KStatefulBrush(); /** * Construct a stateful brush from given color set and foreground role, * using the colors from the given KConfig. * If null, the application's color scheme is used (either the system * default, or one set by KColorSchemeManager). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::ForegroundRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful brush from given color set and background role, * using the colors from the given KConfig (if null, the application's * colors are used). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::BackgroundRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful brush from given color set and decoration role, * using the colors from the given KConfig (if null, the application's * colors are used). */ explicit KStatefulBrush(KColorScheme::ColorSet, KColorScheme::DecorationRole, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful background brush from a specified QBrush (or * QColor, via QBrush's implicit constructor). The various states are * determined from the base QBrush (which fills in the Active state) * according to the same rules used to build stateful color schemes from * the system color scheme. The state effects from the given KConfig are * used (if null, the application's state effects are used). */ explicit KStatefulBrush(const QBrush &, KSharedConfigPtr = KSharedConfigPtr()); /** * Construct a stateful foreground/decoration brush from a specified * QBrush (or QColor, via QBrush's implicit constructor). The various * states are determined from the base QBrush (which fills in the Active * state) according to the same rules used to build stateful color schemes * from the system color scheme. The state effects from the given KConfig * are used (if null, the application's state effects are used). * * @param background The background brush (or color) corresponding to the * KColorScheme::NormalBackground role and QPalette::Active state for this * foreground/decoration color. */ explicit KStatefulBrush(const QBrush &, const QBrush &background, KSharedConfigPtr = KSharedConfigPtr()); /** Construct a copy of another KStatefulBrush. */ KStatefulBrush(const KStatefulBrush &); /** Destructor */ ~KStatefulBrush(); /** Standard assignment operator */ KStatefulBrush &operator=(const KStatefulBrush &); /** * Retrieve the brush for the specified widget state. This is used when you * know explicitly what state is wanted. Otherwise one of overloads is * often more convenient. */ QBrush brush(QPalette::ColorGroup) const; /** * Retrieve the brush, using a QPalette reference to determine the correct * state. Use when your painting code has easy access to the QPalette that * it is supposed to be using. The state used in this instance is the * currentColorGroup of the palette. */ QBrush brush(const QPalette &) const; /** * Retrieve the brush, using a QWidget pointer to determine the correct * state. Use when you have a pointer to the widget that you are painting. * The state used is the current state of the widget. * * @note If you pass an invalid widget, you will get a default brush (i.e. * QBrush()). */ QBrush brush(const QWidget *) const; private: class KStatefulBrushPrivate *d; }; Q_DECLARE_METATYPE(KStatefulBrush) /* so we can pass it in QVariant's */ #endif // KCOLORSCHEME_H