| 1 | /* |
| 2 | * SPDX-FileCopyrightText: 2017 Marco Martin <mart@kde.org> |
| 3 | * SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl> |
| 4 | * |
| 5 | * SPDX-License-Identifier: LGPL-2.0-or-later |
| 6 | */ |
| 7 | |
| 8 | #include "basictheme_p.h" |
| 9 | #include "styleselector.h" |
| 10 | |
| 11 | #include <QFile> |
| 12 | #include <QFontDatabase> |
| 13 | #include <QGuiApplication> |
| 14 | |
| 15 | #include "kirigamiplatform_logging.h" |
| 16 | |
| 17 | namespace Kirigami |
| 18 | { |
| 19 | namespace Platform |
| 20 | { |
| 21 | |
| 22 | BasicThemeDefinition::BasicThemeDefinition(QObject *parent) |
| 23 | : QObject(parent) |
| 24 | { |
| 25 | defaultFont = qGuiApp->font(); |
| 26 | |
| 27 | smallFont = QFontDatabase::systemFont(type: QFontDatabase::SmallestReadableFont); |
| 28 | } |
| 29 | |
| 30 | void BasicThemeDefinition::syncToQml(PlatformTheme *object) |
| 31 | { |
| 32 | auto item = qobject_cast<QQuickItem *>(o: object->parent()); |
| 33 | if (item && qmlAttachedPropertiesObject<PlatformTheme>(obj: item, create: false) == object) { |
| 34 | Q_EMIT sync(object: item); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | BasicThemeInstance::BasicThemeInstance(QObject *parent) |
| 39 | : QObject(parent) |
| 40 | { |
| 41 | } |
| 42 | |
| 43 | BasicThemeDefinition &BasicThemeInstance::themeDefinition(QQmlEngine *engine) |
| 44 | { |
| 45 | if (m_themeDefinition) { |
| 46 | return *m_themeDefinition; |
| 47 | } |
| 48 | |
| 49 | if (!engine) { |
| 50 | qCWarning(KirigamiPlatform) << "No QML engine found, using default Basic theme." ; |
| 51 | m_themeDefinition = std::make_unique<BasicThemeDefinition>(); |
| 52 | } else { |
| 53 | auto themeUrl = StyleSelector::componentUrl(QStringLiteral("Theme.qml" )); |
| 54 | QQmlComponent component(engine); |
| 55 | component.loadUrl(url: themeUrl); |
| 56 | |
| 57 | if (auto themeDefinition = qobject_cast<BasicThemeDefinition *>(object: component.create())) { |
| 58 | m_themeDefinition.reset(p: themeDefinition); |
| 59 | } else { |
| 60 | const auto errors = component.errors(); |
| 61 | for (auto error : errors) { |
| 62 | qCWarning(KirigamiPlatform) << error.toString(); |
| 63 | } |
| 64 | |
| 65 | qCWarning(KirigamiPlatform) << "Invalid Theme file, using default Basic theme." ; |
| 66 | m_themeDefinition = std::make_unique<BasicThemeDefinition>(); |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | connect(sender: m_themeDefinition.get(), signal: &BasicThemeDefinition::changed, context: this, slot: &BasicThemeInstance::onDefinitionChanged); |
| 71 | |
| 72 | return *m_themeDefinition; |
| 73 | } |
| 74 | |
| 75 | void BasicThemeInstance::onDefinitionChanged() |
| 76 | { |
| 77 | for (auto watcher : std::as_const(t&: watchers)) { |
| 78 | watcher->sync(); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | Q_GLOBAL_STATIC(BasicThemeInstance, basicThemeInstance) |
| 83 | |
| 84 | BasicTheme::BasicTheme(QObject *parent) |
| 85 | : PlatformTheme(parent) |
| 86 | { |
| 87 | basicThemeInstance()->watchers.append(t: this); |
| 88 | |
| 89 | sync(); |
| 90 | } |
| 91 | |
| 92 | BasicTheme::~BasicTheme() |
| 93 | { |
| 94 | basicThemeInstance()->watchers.removeOne(t: this); |
| 95 | } |
| 96 | |
| 97 | void BasicTheme::sync() |
| 98 | { |
| 99 | PlatformThemeChangeTracker tracker{this}; |
| 100 | |
| 101 | auto &definition = basicThemeInstance()->themeDefinition(engine: qmlEngine(parent())); |
| 102 | |
| 103 | switch (colorSet()) { |
| 104 | case BasicTheme::Button: |
| 105 | setTextColor(tint(color: definition.buttonTextColor)); |
| 106 | setBackgroundColor(tint(color: definition.buttonBackgroundColor)); |
| 107 | setAlternateBackgroundColor(tint(color: definition.buttonAlternateBackgroundColor)); |
| 108 | setHoverColor(tint(color: definition.buttonHoverColor)); |
| 109 | setFocusColor(tint(color: definition.buttonFocusColor)); |
| 110 | break; |
| 111 | case BasicTheme::View: |
| 112 | setTextColor(tint(color: definition.viewTextColor)); |
| 113 | setBackgroundColor(tint(color: definition.viewBackgroundColor)); |
| 114 | setAlternateBackgroundColor(tint(color: definition.viewAlternateBackgroundColor)); |
| 115 | setHoverColor(tint(color: definition.viewHoverColor)); |
| 116 | setFocusColor(tint(color: definition.viewFocusColor)); |
| 117 | break; |
| 118 | case BasicTheme::Selection: |
| 119 | setTextColor(tint(color: definition.selectionTextColor)); |
| 120 | setBackgroundColor(tint(color: definition.selectionBackgroundColor)); |
| 121 | setAlternateBackgroundColor(tint(color: definition.selectionAlternateBackgroundColor)); |
| 122 | setHoverColor(tint(color: definition.selectionHoverColor)); |
| 123 | setFocusColor(tint(color: definition.selectionFocusColor)); |
| 124 | break; |
| 125 | case BasicTheme::Tooltip: |
| 126 | setTextColor(tint(color: definition.tooltipTextColor)); |
| 127 | setBackgroundColor(tint(color: definition.tooltipBackgroundColor)); |
| 128 | setAlternateBackgroundColor(tint(color: definition.tooltipAlternateBackgroundColor)); |
| 129 | setHoverColor(tint(color: definition.tooltipHoverColor)); |
| 130 | setFocusColor(tint(color: definition.tooltipFocusColor)); |
| 131 | break; |
| 132 | case BasicTheme::Complementary: |
| 133 | setTextColor(tint(color: definition.complementaryTextColor)); |
| 134 | setBackgroundColor(tint(color: definition.complementaryBackgroundColor)); |
| 135 | setAlternateBackgroundColor(tint(color: definition.complementaryAlternateBackgroundColor)); |
| 136 | setHoverColor(tint(color: definition.complementaryHoverColor)); |
| 137 | setFocusColor(tint(color: definition.complementaryFocusColor)); |
| 138 | break; |
| 139 | case BasicTheme::Window: |
| 140 | default: |
| 141 | setTextColor(tint(color: definition.textColor)); |
| 142 | setBackgroundColor(tint(color: definition.backgroundColor)); |
| 143 | setAlternateBackgroundColor(tint(color: definition.alternateBackgroundColor)); |
| 144 | setHoverColor(tint(color: definition.hoverColor)); |
| 145 | setFocusColor(tint(color: definition.focusColor)); |
| 146 | break; |
| 147 | } |
| 148 | |
| 149 | setDisabledTextColor(tint(color: definition.disabledTextColor)); |
| 150 | setHighlightColor(tint(color: definition.highlightColor)); |
| 151 | setHighlightedTextColor(tint(color: definition.highlightedTextColor)); |
| 152 | setActiveTextColor(tint(color: definition.activeTextColor)); |
| 153 | setActiveBackgroundColor(tint(color: definition.activeBackgroundColor)); |
| 154 | setLinkColor(tint(color: definition.linkColor)); |
| 155 | setLinkBackgroundColor(tint(color: definition.linkBackgroundColor)); |
| 156 | setVisitedLinkColor(tint(color: definition.visitedLinkColor)); |
| 157 | setVisitedLinkBackgroundColor(tint(color: definition.visitedLinkBackgroundColor)); |
| 158 | setNegativeTextColor(tint(color: definition.negativeTextColor)); |
| 159 | setNegativeBackgroundColor(tint(color: definition.negativeBackgroundColor)); |
| 160 | setNeutralTextColor(tint(color: definition.neutralTextColor)); |
| 161 | setNeutralBackgroundColor(tint(color: definition.neutralBackgroundColor)); |
| 162 | setPositiveTextColor(tint(color: definition.positiveTextColor)); |
| 163 | setPositiveBackgroundColor(tint(color: definition.positiveBackgroundColor)); |
| 164 | |
| 165 | setDefaultFont(definition.defaultFont); |
| 166 | setSmallFont(definition.smallFont); |
| 167 | } |
| 168 | |
| 169 | bool BasicTheme::event(QEvent *event) |
| 170 | { |
| 171 | if (event->type() == PlatformThemeEvents::DataChangedEvent::type) { |
| 172 | sync(); |
| 173 | } |
| 174 | |
| 175 | if (event->type() == PlatformThemeEvents::ColorSetChangedEvent::type) { |
| 176 | sync(); |
| 177 | } |
| 178 | |
| 179 | if (event->type() == PlatformThemeEvents::ColorGroupChangedEvent::type) { |
| 180 | sync(); |
| 181 | } |
| 182 | |
| 183 | if (event->type() == PlatformThemeEvents::ColorChangedEvent::type) { |
| 184 | basicThemeInstance()->themeDefinition(engine: qmlEngine(parent())).syncToQml(object: this); |
| 185 | } |
| 186 | |
| 187 | if (event->type() == PlatformThemeEvents::FontChangedEvent::type) { |
| 188 | basicThemeInstance()->themeDefinition(engine: qmlEngine(parent())).syncToQml(object: this); |
| 189 | } |
| 190 | |
| 191 | return PlatformTheme::event(event); |
| 192 | } |
| 193 | |
| 194 | QColor BasicTheme::tint(const QColor &color) |
| 195 | { |
| 196 | if (QQuickItem *item = qobject_cast<QQuickItem *>(o: parent()); item && !item->isEnabled()) { |
| 197 | return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF() * 0.8); |
| 198 | } |
| 199 | switch (colorGroup()) { |
| 200 | case PlatformTheme::Inactive: |
| 201 | return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF()); |
| 202 | case PlatformTheme::Disabled: |
| 203 | return QColor::fromHsvF(h: color.hueF(), s: color.saturationF() * 0.5, v: color.valueF() * 0.8); |
| 204 | default: |
| 205 | return color; |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | #include "moc_basictheme_p.cpp" |
| 213 | |