File indexing completed on 2024-05-05 03:56:27

0001 /*
0002  *  SPDX-FileCopyrightText: 2020 Jonah BrĂ¼chert <jbb@kaidan.im>
0003  *  SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
0004  *
0005  *  SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "units.h"
0009 
0010 #include <QFont>
0011 #include <QFontMetrics>
0012 #include <QGuiApplication>
0013 #include <QQmlComponent>
0014 #include <QQmlEngine>
0015 #include <QQuickStyle>
0016 #include <QStyleHints>
0017 
0018 #include <chrono>
0019 #include <cmath>
0020 
0021 #include "kirigamiplatform_logging.h"
0022 #include "platformpluginfactory.h"
0023 
0024 namespace Kirigami
0025 {
0026 namespace Platform
0027 {
0028 
0029 class UnitsPrivate
0030 {
0031     Q_DISABLE_COPY(UnitsPrivate)
0032 
0033 public:
0034     explicit UnitsPrivate(Units *units)
0035         // Cache font so we don't have to go through QVariant and property every time
0036         : fontMetrics(QFontMetricsF(QGuiApplication::font()))
0037         , gridUnit(std::ceil(fontMetrics.height()))
0038         , smallSpacing(std::floor(gridUnit / 4))
0039         , mediumSpacing(std::round(smallSpacing * 1.5))
0040         , largeSpacing(smallSpacing * 2)
0041         , veryLongDuration(400)
0042         , longDuration(200)
0043         , shortDuration(100)
0044         , veryShortDuration(50)
0045         , humanMoment(2000)
0046         , toolTipDelay(700)
0047         , iconSizes(new IconSizes(units))
0048     {
0049     }
0050 
0051     // Font metrics used for Units.
0052     // TextMetrics uses QFontMetricsF internally, so this should do the same
0053     QFontMetricsF fontMetrics;
0054 
0055     // units
0056     int gridUnit;
0057     int smallSpacing;
0058     int mediumSpacing;
0059     int largeSpacing;
0060 
0061     // durations
0062     int veryLongDuration;
0063     int longDuration;
0064     int shortDuration;
0065     int veryShortDuration;
0066     int humanMoment;
0067     int toolTipDelay;
0068 
0069     IconSizes *const iconSizes;
0070 
0071     // To prevent overriding custom set units if the font changes
0072     bool customUnitsSet = false;
0073 };
0074 
0075 Units::~Units() = default;
0076 
0077 Units::Units(QObject *parent)
0078     : QObject(parent)
0079     , d(std::make_unique<UnitsPrivate>(this))
0080 {
0081     qGuiApp->installEventFilter(this);
0082 }
0083 
0084 int Units::gridUnit() const
0085 {
0086     return d->gridUnit;
0087 }
0088 
0089 void Units::setGridUnit(int size)
0090 {
0091     if (d->gridUnit == size) {
0092         return;
0093     }
0094 
0095     d->gridUnit = size;
0096     d->customUnitsSet = true;
0097     Q_EMIT gridUnitChanged();
0098 }
0099 
0100 int Units::smallSpacing() const
0101 {
0102     return d->smallSpacing;
0103 }
0104 
0105 void Units::setSmallSpacing(int size)
0106 {
0107     if (d->smallSpacing == size) {
0108         return;
0109     }
0110 
0111     d->smallSpacing = size;
0112     d->customUnitsSet = true;
0113     Q_EMIT smallSpacingChanged();
0114 }
0115 
0116 int Units::mediumSpacing() const
0117 {
0118     return d->mediumSpacing;
0119 }
0120 
0121 void Units::setMediumSpacing(int size)
0122 {
0123     if (d->mediumSpacing == size) {
0124         return;
0125     }
0126 
0127     d->mediumSpacing = size;
0128     d->customUnitsSet = true;
0129     Q_EMIT mediumSpacingChanged();
0130 }
0131 
0132 int Units::largeSpacing() const
0133 {
0134     return d->largeSpacing;
0135 }
0136 
0137 void Units::setLargeSpacing(int size)
0138 {
0139     if (d->largeSpacing) {
0140         return;
0141     }
0142 
0143     d->largeSpacing = size;
0144     d->customUnitsSet = true;
0145     Q_EMIT largeSpacingChanged();
0146 }
0147 
0148 int Units::veryLongDuration() const
0149 {
0150     return d->veryLongDuration;
0151 }
0152 
0153 void Units::setVeryLongDuration(int duration)
0154 {
0155     if (d->veryLongDuration == duration) {
0156         return;
0157     }
0158 
0159     d->veryLongDuration = duration;
0160     Q_EMIT veryLongDurationChanged();
0161 }
0162 
0163 int Units::longDuration() const
0164 {
0165     return d->longDuration;
0166 }
0167 
0168 void Units::setLongDuration(int duration)
0169 {
0170     if (d->longDuration == duration) {
0171         return;
0172     }
0173 
0174     d->longDuration = duration;
0175     Q_EMIT longDurationChanged();
0176 }
0177 
0178 int Units::shortDuration() const
0179 {
0180     return d->shortDuration;
0181 }
0182 
0183 void Units::setShortDuration(int duration)
0184 {
0185     if (d->shortDuration == duration) {
0186         return;
0187     }
0188 
0189     d->shortDuration = duration;
0190     Q_EMIT shortDurationChanged();
0191 }
0192 
0193 int Units::veryShortDuration() const
0194 {
0195     return d->veryShortDuration;
0196 }
0197 
0198 void Units::setVeryShortDuration(int duration)
0199 {
0200     if (d->veryShortDuration == duration) {
0201         return;
0202     }
0203 
0204     d->veryShortDuration = duration;
0205     Q_EMIT veryShortDurationChanged();
0206 }
0207 
0208 int Units::humanMoment() const
0209 {
0210     return d->humanMoment;
0211 }
0212 
0213 void Units::setHumanMoment(int duration)
0214 {
0215     if (d->humanMoment == duration) {
0216         return;
0217     }
0218 
0219     d->humanMoment = duration;
0220     Q_EMIT humanMomentChanged();
0221 }
0222 
0223 int Units::toolTipDelay() const
0224 {
0225     return d->toolTipDelay;
0226 }
0227 
0228 void Units::setToolTipDelay(int delay)
0229 {
0230     if (d->toolTipDelay == delay) {
0231         return;
0232     }
0233 
0234     d->toolTipDelay = delay;
0235     Q_EMIT toolTipDelayChanged();
0236 }
0237 
0238 Units *Units::create(QQmlEngine *qmlEngine, [[maybe_unused]] QJSEngine *jsEngine)
0239 {
0240 #ifndef KIRIGAMI_BUILD_TYPE_STATIC
0241     const QString pluginName = qmlEngine->property("_kirigamiTheme").toString();
0242 
0243     auto plugin = PlatformPluginFactory::findPlugin(pluginName);
0244     if (!plugin && !pluginName.isEmpty()) {
0245         plugin = PlatformPluginFactory::findPlugin();
0246     }
0247 
0248     if (plugin) {
0249         return plugin->createUnits(qmlEngine);
0250     }
0251 #endif
0252     // Fall back to the default units implementation
0253     return new Units(qmlEngine);
0254 }
0255 
0256 bool Units::eventFilter([[maybe_unused]] QObject *watched, QEvent *event)
0257 {
0258     if (event->type() == QEvent::ApplicationFontChange) {
0259         d->fontMetrics = QFontMetricsF(qGuiApp->font());
0260 
0261         if (d->customUnitsSet) {
0262             return false;
0263         }
0264 
0265         d->gridUnit = std::ceil(d->fontMetrics.height());
0266         Q_EMIT gridUnitChanged();
0267         d->smallSpacing = std::floor(d->gridUnit / 4);
0268         Q_EMIT smallSpacingChanged();
0269         d->mediumSpacing = std::round(d->smallSpacing * 1.5);
0270         Q_EMIT mediumSpacingChanged();
0271         d->largeSpacing = d->smallSpacing * 2;
0272         Q_EMIT largeSpacingChanged();
0273         Q_EMIT d->iconSizes->sizeForLabelsChanged();
0274     }
0275     return false;
0276 }
0277 
0278 IconSizes *Units::iconSizes() const
0279 {
0280     return d->iconSizes;
0281 }
0282 
0283 IconSizes::IconSizes(Units *units)
0284     : QObject(units)
0285     , m_units(units)
0286 {
0287 }
0288 
0289 int IconSizes::roundedIconSize(int size) const
0290 {
0291     if (size < 16) {
0292         return size;
0293     }
0294 
0295     if (size < 22) {
0296         return 16;
0297     }
0298 
0299     if (size < 32) {
0300         return 22;
0301     }
0302 
0303     if (size < 48) {
0304         return 32;
0305     }
0306 
0307     if (size < 64) {
0308         return 48;
0309     }
0310 
0311     return size;
0312 }
0313 
0314 int IconSizes::sizeForLabels() const
0315 {
0316     // gridUnit is the height of textMetrics
0317     return roundedIconSize(m_units->d->fontMetrics.height());
0318 }
0319 
0320 int IconSizes::small() const
0321 {
0322     return 16;
0323 }
0324 
0325 int IconSizes::smallMedium() const
0326 {
0327     return 22;
0328 }
0329 
0330 int IconSizes::medium() const
0331 {
0332     return 32;
0333 }
0334 
0335 int IconSizes::large() const
0336 {
0337     return 48;
0338 }
0339 
0340 int IconSizes::huge() const
0341 {
0342     return 64;
0343 }
0344 
0345 int IconSizes::enormous() const
0346 {
0347     return 128;
0348 }
0349 }
0350 }
0351 
0352 #include "moc_units.cpp"