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"