File indexing completed on 2024-05-12 15:58:22

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_image_config.h"
0008 
0009 #include <ksharedconfig.h>
0010 
0011 #include <KoConfig.h>
0012 #include <KoColorProfile.h>
0013 #include <KoColorSpaceRegistry.h>
0014 #include <KoColorConversionTransformation.h>
0015 #include <kis_properties_configuration.h>
0016 
0017 #include "kis_debug.h"
0018 
0019 #include <QThread>
0020 #include <QApplication>
0021 #include <QColor>
0022 #include <QDir>
0023 
0024 #include "kis_global.h"
0025 #include <cmath>
0026 #include <QTemporaryFile>
0027 
0028 #ifdef Q_OS_MACOS
0029 #include <errno.h>
0030 #endif
0031 
0032 KisImageConfig::KisImageConfig(bool readOnly)
0033     : m_config(KSharedConfig::openConfig()->group(QString()))
0034     , m_readOnly(readOnly)
0035 {
0036     if (!readOnly) {
0037         KIS_SAFE_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
0038     }
0039 #ifdef Q_OS_MACOS
0040     // clear /var/folders/ swap path set by old broken Krita swap implementation in order to use new default swap dir.
0041     QString swap = m_config.readEntry("swaplocation", "");
0042     if (swap.startsWith("/var/folders/")) {
0043         m_config.deleteEntry("swaplocation");
0044     }
0045 #endif
0046 }
0047 
0048 KisImageConfig::~KisImageConfig()
0049 {
0050     if (m_readOnly) return;
0051 
0052     if (qApp->thread() != QThread::currentThread()) {
0053         dbgKrita << "KisImageConfig: requested config synchronization from nonGUI thread! Called from" << kisBacktrace();
0054         return;
0055     }
0056 
0057     m_config.sync();
0058 }
0059 
0060 bool KisImageConfig::enableProgressReporting(bool requestDefault) const
0061 {
0062     return !requestDefault ?
0063         m_config.readEntry("enableProgressReporting", true) : true;
0064 }
0065 
0066 void KisImageConfig::setEnableProgressReporting(bool value)
0067 {
0068     m_config.writeEntry("enableProgressReporting", value);
0069 }
0070 
0071 bool KisImageConfig::enablePerfLog(bool requestDefault) const
0072 {
0073     return !requestDefault ?
0074         m_config.readEntry("enablePerfLog", false) :false;
0075 }
0076 
0077 void KisImageConfig::setEnablePerfLog(bool value)
0078 {
0079     m_config.writeEntry("enablePerfLog", value);
0080 }
0081 
0082 qreal KisImageConfig::transformMaskOffBoundsReadArea() const
0083 {
0084     return m_config.readEntry("transformMaskOffBoundsReadArea", 0.5);
0085 }
0086 
0087 int KisImageConfig::updatePatchHeight() const
0088 {
0089     int patchHeight = m_config.readEntry("updatePatchHeight", 512);
0090     if (patchHeight <= 0) return 512;
0091     return patchHeight;
0092 }
0093 
0094 void KisImageConfig::setUpdatePatchHeight(int value)
0095 {
0096     m_config.writeEntry("updatePatchHeight", value);
0097 }
0098 
0099 int KisImageConfig::updatePatchWidth() const
0100 {
0101     int patchWidth = m_config.readEntry("updatePatchWidth", 512);
0102     if (patchWidth <= 0) return 512;
0103     return patchWidth;
0104 }
0105 
0106 void KisImageConfig::setUpdatePatchWidth(int value)
0107 {
0108     m_config.writeEntry("updatePatchWidth", value);
0109 }
0110 
0111 qreal KisImageConfig::maxCollectAlpha() const
0112 {
0113     return m_config.readEntry("maxCollectAlpha", 2.5);
0114 }
0115 
0116 qreal KisImageConfig::maxMergeAlpha() const
0117 {
0118     return m_config.readEntry("maxMergeAlpha", 1.);
0119 }
0120 
0121 qreal KisImageConfig::maxMergeCollectAlpha() const
0122 {
0123     return m_config.readEntry("maxMergeCollectAlpha", 1.5);
0124 }
0125 
0126 qreal KisImageConfig::schedulerBalancingRatio() const
0127 {
0128     /**
0129      * updates-queue-size / strokes-queue-size
0130      */
0131     return m_config.readEntry("schedulerBalancingRatio", 100.);
0132 }
0133 
0134 void KisImageConfig::setSchedulerBalancingRatio(qreal value)
0135 {
0136     m_config.writeEntry("schedulerBalancingRatio", value);
0137 }
0138 
0139 int KisImageConfig::maxSwapSize(bool requestDefault) const
0140 {
0141     return !requestDefault ?
0142         m_config.readEntry("maxSwapSize", 4096) : 4096; // in MiB
0143 }
0144 
0145 void KisImageConfig::setMaxSwapSize(int value)
0146 {
0147     m_config.writeEntry("maxSwapSize", value);
0148 }
0149 
0150 int KisImageConfig::swapSlabSize() const
0151 {
0152     return m_config.readEntry("swapSlabSize", 64); // in MiB
0153 }
0154 
0155 void KisImageConfig::setSwapSlabSize(int value)
0156 {
0157     m_config.writeEntry("swapSlabSize", value);
0158 }
0159 
0160 int KisImageConfig::swapWindowSize() const
0161 {
0162     return m_config.readEntry("swapWindowSize", 16); // in MiB
0163 }
0164 
0165 void KisImageConfig::setSwapWindowSize(int value)
0166 {
0167     m_config.writeEntry("swapWindowSize", value);
0168 }
0169 
0170 int KisImageConfig::tilesHardLimit() const
0171 {
0172     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
0173     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
0174 
0175     return totalRAM() * hp * (1 - pp);
0176 }
0177 
0178 int KisImageConfig::tilesSoftLimit() const
0179 {
0180     qreal sp = qreal(memorySoftLimitPercent()) / 100.0;
0181 
0182     return tilesHardLimit() * sp;
0183 }
0184 
0185 int KisImageConfig::poolLimit() const
0186 {
0187     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
0188     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
0189 
0190     return totalRAM() * hp * pp;
0191 }
0192 
0193 qreal KisImageConfig::memoryHardLimitPercent(bool requestDefault) const
0194 {
0195     return !requestDefault ?
0196         m_config.readEntry("memoryHardLimitPercent", 50.) : 50.;
0197 }
0198 
0199 void KisImageConfig::setMemoryHardLimitPercent(qreal value)
0200 {
0201     m_config.writeEntry("memoryHardLimitPercent", value);
0202 }
0203 
0204 qreal KisImageConfig::memorySoftLimitPercent(bool requestDefault) const
0205 {
0206     return !requestDefault ?
0207         m_config.readEntry("memorySoftLimitPercent", 2.) : 2.;
0208 }
0209 
0210 void KisImageConfig::setMemorySoftLimitPercent(qreal value)
0211 {
0212     m_config.writeEntry("memorySoftLimitPercent", value);
0213 }
0214 
0215 qreal KisImageConfig::memoryPoolLimitPercent(bool requestDefault) const
0216 {
0217     return !requestDefault ?
0218         m_config.readEntry("memoryPoolLimitPercent", 0.0) : 0.0;
0219 }
0220 
0221 void KisImageConfig::setMemoryPoolLimitPercent(qreal value)
0222 {
0223     m_config.writeEntry("memoryPoolLimitPercent", value);
0224 }
0225 
0226 QString KisImageConfig::safelyGetWritableTempLocation(const QString &suffix, const QString &configKey, bool requestDefault) const
0227 {
0228 #ifdef Q_OS_MACOS
0229     // On OSX, QDir::tempPath() gives us a folder we cannot reply upon (usually
0230     // something like /var/folders/.../...) and that will have vanished when we
0231     // try to create the tmp file in KisMemoryWindow::KisMemoryWindow using
0232     // swapFileTemplate. thus, we just pick the home folder if swapDir does not
0233     // tell us otherwise.
0234 
0235     // the other option here would be to use a "garbled name" temp file (i.e. no name
0236     // KRITA_SWAP_FILE_XXXXXX) in an obscure /var/folders place, which is not
0237     // nice to the user. having a clearly named swap file in the home folder is
0238     // much nicer to Krita's users.
0239 
0240     // furthermore, this is just a default and swapDir can always be configured
0241     // to another location.
0242 
0243     QString swap = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/' + suffix;
0244 #else
0245     Q_UNUSED(suffix);
0246     QString swap = QDir::tempPath();
0247 #endif
0248     if (requestDefault) {
0249        return swap;
0250     }
0251     const QString configuredSwap = m_config.readEntry(configKey, swap);
0252     if (!configuredSwap.isEmpty()) {
0253         swap = configuredSwap;
0254     }
0255 
0256     QString chosenLocation;
0257     QStringList proposedSwapLocations;
0258     proposedSwapLocations << swap;
0259     proposedSwapLocations << QDir::tempPath();
0260     proposedSwapLocations << QDir::homePath();
0261 
0262     Q_FOREACH (const QString location, proposedSwapLocations) {
0263         if (!QFileInfo(location).isWritable()) continue;
0264 
0265         /**
0266          * On NTFS, isWritable() doesn't check for attributes due to performance
0267          * reasons, so we should try it in a brute-force way...
0268          * (yes, there is a hacky-global-variable workaround, but let's be safe)
0269          */
0270         QTemporaryFile tempFile;
0271         tempFile.setFileTemplate(location + '/' + "krita_test_swap_location");
0272         if (tempFile.open() && !tempFile.fileName().isEmpty()) {
0273             chosenLocation = location;
0274             break;
0275         }
0276     }
0277 
0278     if (chosenLocation.isEmpty()) {
0279         qCritical() << "CRITICAL: no writable location for a swap file found! Tried the following paths:" << proposedSwapLocations;
0280         qCritical() << "CRITICAL: hope I don't crash...";
0281         chosenLocation = swap;
0282     }
0283 
0284     if (chosenLocation != swap) {
0285         qWarning() << "WARNING: configured swap location is not writable, using a fall-back location" << swap << "->" << chosenLocation;
0286     }
0287 
0288     return chosenLocation;
0289 }
0290 
0291 
0292 QString KisImageConfig::swapDir(bool requestDefault)
0293 {
0294     return safelyGetWritableTempLocation("swap", "swaplocation", requestDefault);
0295 }
0296 
0297 void KisImageConfig::setSwapDir(const QString &swapDir)
0298 {
0299     m_config.writeEntry("swaplocation", swapDir);
0300 }
0301 
0302 int KisImageConfig::numberOfOnionSkins() const
0303 {
0304     return m_config.readEntry("numberOfOnionSkins", 10);
0305 }
0306 
0307 void KisImageConfig::setNumberOfOnionSkins(int value)
0308 {
0309     m_config.writeEntry("numberOfOnionSkins", value);
0310 }
0311 
0312 int KisImageConfig::onionSkinTintFactor() const
0313 {
0314     return m_config.readEntry("onionSkinTintFactor", 192);
0315 }
0316 
0317 void KisImageConfig::setOnionSkinTintFactor(int value)
0318 {
0319     m_config.writeEntry("onionSkinTintFactor", value);
0320 }
0321 
0322 int KisImageConfig::onionSkinOpacity(int offset) const
0323 {
0324     int value = m_config.readEntry("onionSkinOpacity_" + QString::number(offset), -1);
0325 
0326     if (value < 0) {
0327         const int num = numberOfOnionSkins();
0328         const qreal dx = qreal(qAbs(offset)) / num;
0329         value = 0.7 * exp(-pow2(dx) / 0.5) * 255;
0330     }
0331 
0332     return value;
0333 }
0334 
0335 void KisImageConfig::setOnionSkinOpacity(int offset, int value)
0336 {
0337     m_config.writeEntry("onionSkinOpacity_" + QString::number(offset), value);
0338 }
0339 
0340 bool KisImageConfig::onionSkinState(int offset) const
0341 {
0342     bool enableByDefault = (qAbs(offset) <= 2);
0343     return m_config.readEntry("onionSkinState_" + QString::number(offset), enableByDefault);
0344 }
0345 
0346 void KisImageConfig::setOnionSkinState(int offset, bool value)
0347 {
0348     m_config.writeEntry("onionSkinState_" + QString::number(offset), value);
0349 }
0350 
0351 QColor KisImageConfig::onionSkinTintColorBackward() const
0352 {
0353     return m_config.readEntry("onionSkinTintColorBackward", QColor(Qt::red));
0354 }
0355 
0356 void KisImageConfig::setOnionSkinTintColorBackward(const QColor &value)
0357 {
0358     m_config.writeEntry("onionSkinTintColorBackward", value);
0359 }
0360 
0361 QColor KisImageConfig::onionSkinTintColorForward() const
0362 {
0363     return m_config.readEntry("oninSkinTintColorForward", QColor(Qt::green));
0364 }
0365 
0366 void KisImageConfig::setOnionSkinTintColorForward(const QColor &value)
0367 {
0368     m_config.writeEntry("oninSkinTintColorForward", value);
0369 }
0370 
0371 bool KisImageConfig::autoKeyEnabled(bool requestDefault) const
0372 {
0373     return !requestDefault ?
0374         m_config.readEntry("lazyFrameCreationEnabled", true) : true;
0375 }
0376 
0377 void KisImageConfig::setAutoKeyEnabled(bool value)
0378 {
0379     m_config.writeEntry("lazyFrameCreationEnabled", value);
0380 }
0381 
0382 bool KisImageConfig::autoKeyModeDuplicate(bool requestDefault) const
0383 {
0384     return !requestDefault ?
0385         m_config.readEntry("lazyFrameModeDuplicate", true) : true;
0386 }
0387 
0388 void KisImageConfig::setAutoKeyModeDuplicate(bool value)
0389 {
0390     m_config.writeEntry("lazyFrameModeDuplicate", value);
0391 }
0392 
0393 #if defined Q_OS_LINUX
0394 #include <sys/sysinfo.h>
0395 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
0396 #include <sys/sysctl.h>
0397 #elif defined Q_OS_WIN
0398 #include <windows.h>
0399 #elif defined Q_OS_MACOS
0400 #include <sys/types.h>
0401 #include <sys/sysctl.h>
0402 #endif
0403 
0404 int KisImageConfig::totalRAM()
0405 {
0406     // let's think that default memory size is 1000MiB
0407     int totalMemory = 1000; // MiB
0408     int error = 1;
0409 
0410 #if defined Q_OS_LINUX
0411     struct sysinfo info;
0412 
0413     error = sysinfo(&info);
0414     if(!error) {
0415         totalMemory = info.totalram * info.mem_unit / (1UL << 20);
0416     }
0417 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
0418     u_long physmem;
0419 #   if defined HW_PHYSMEM64 // NetBSD only
0420     int mib[] = {CTL_HW, HW_PHYSMEM64};
0421 #   else
0422     int mib[] = {CTL_HW, HW_PHYSMEM};
0423 #   endif
0424     size_t len = sizeof(physmem);
0425 
0426     error = sysctl(mib, 2, &physmem, &len, 0, 0);
0427     if(!error) {
0428         totalMemory = physmem >> 20;
0429     }
0430 #elif defined Q_OS_WIN
0431     MEMORYSTATUSEX status;
0432     status.dwLength = sizeof(status);
0433     error  = !GlobalMemoryStatusEx(&status);
0434 
0435     if (!error) {
0436         totalMemory = status.ullTotalPhys >> 20;
0437     }
0438 
0439     // For 32 bit windows, the total memory available is at max the 2GB per process memory limit.
0440 #   if defined ENV32BIT
0441     totalMemory = qMin(totalMemory, 2000);
0442 #   endif
0443 #elif defined Q_OS_MACOS
0444     int mib[2] = { CTL_HW, HW_MEMSIZE };
0445     u_int namelen = sizeof(mib) / sizeof(mib[0]);
0446     uint64_t size;
0447     size_t len = sizeof(size);
0448 
0449     errno = 0;
0450     if (sysctl(mib, namelen, &size, &len, 0, 0) >= 0) {
0451         totalMemory = size >> 20;
0452         error = 0;
0453     }
0454     else {
0455         dbgKrita << "sysctl(\"hw.memsize\") raised error" << strerror(errno);
0456     }
0457 #endif
0458 
0459     if (error) {
0460         warnKrita << "Cannot get the size of your RAM. Using 1 GiB by default.";
0461     }
0462 
0463     return totalMemory;
0464 }
0465 
0466 bool KisImageConfig::showAdditionalOnionSkinsSettings(bool requestDefault) const
0467 {
0468     return !requestDefault ?
0469         m_config.readEntry("showAdditionalOnionSkinsSettings", true) : true;
0470 }
0471 
0472 void KisImageConfig::setShowAdditionalOnionSkinsSettings(bool value)
0473 {
0474     m_config.writeEntry("showAdditionalOnionSkinsSettings", value);
0475 }
0476 
0477 int KisImageConfig::defaultFrameColorLabel() const
0478 {
0479     return m_config.readEntry("defaultFrameColorLabel", 0);
0480 }
0481 
0482 void KisImageConfig::setDefaultFrameColorLabel(int label)
0483 {
0484     m_config.writeEntry("defaultFrameColorLabel", label);
0485 }
0486 
0487 KisProofingConfigurationSP KisImageConfig::defaultProofingconfiguration()
0488 {
0489     KisProofingConfiguration *proofingConfig= new KisProofingConfiguration();
0490     proofingConfig->proofingProfile = m_config.readEntry("defaultProofingProfileName", "Chemical proof");
0491     proofingConfig->proofingModel = m_config.readEntry("defaultProofingProfileModel", "CMYKA");
0492     proofingConfig->proofingDepth = m_config.readEntry("defaultProofingProfileDepth", "U8");
0493     proofingConfig->intent = (KoColorConversionTransformation::Intent)m_config.readEntry("defaultProofingProfileIntent", 3);
0494     if (m_config.readEntry("defaultProofingBlackpointCompensation", true)) {
0495         proofingConfig->conversionFlags  |= KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
0496     } else {
0497         proofingConfig->conversionFlags  = proofingConfig->conversionFlags & ~KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
0498     }
0499     QColor def(Qt::green);
0500     m_config.readEntry("defaultProofingGamutwarning", def);
0501     KoColor col(KoColorSpaceRegistry::instance()->rgb8());
0502     col.fromQColor(def);
0503     col.setOpacity(1.0);
0504     proofingConfig->warningColor = col;
0505     proofingConfig->adaptationState = (double)m_config.readEntry("defaultProofingAdaptationState", 1.0);
0506     return toQShared(proofingConfig);
0507 }
0508 
0509 void KisImageConfig::setDefaultProofingConfig(const KoColorSpace *proofingSpace, int proofingIntent, bool blackPointCompensation, KoColor warningColor, double adaptationState)
0510 {
0511     if (!proofingSpace || !proofingSpace->profile()) {
0512         return;
0513     }
0514 
0515     m_config.writeEntry("defaultProofingProfileName", proofingSpace->profile()->name());
0516     m_config.writeEntry("defaultProofingProfileModel", proofingSpace->colorModelId().id());
0517     m_config.writeEntry("defaultProofingProfileDepth", proofingSpace->colorDepthId().id());
0518     m_config.writeEntry("defaultProofingProfileIntent", proofingIntent);
0519     m_config.writeEntry("defaultProofingBlackpointCompensation", blackPointCompensation);
0520     QColor c;
0521     c = warningColor.toQColor();
0522     m_config.writeEntry("defaultProofingGamutwarning", c);
0523     m_config.writeEntry("defaultProofingAdaptationState",adaptationState);
0524 }
0525 
0526 bool KisImageConfig::useLodForColorizeMask(bool requestDefault) const
0527 {
0528     return !requestDefault ?
0529         m_config.readEntry("useLodForColorizeMask", false) : false;
0530 }
0531 
0532 void KisImageConfig::setUseLodForColorizeMask(bool value)
0533 {
0534     m_config.writeEntry("useLodForColorizeMask", value);
0535 }
0536 
0537 int KisImageConfig::maxNumberOfThreads(bool defaultValue) const
0538 {
0539     return (defaultValue ? QThread::idealThreadCount() : m_config.readEntry("maxNumberOfThreads", QThread::idealThreadCount()));
0540 }
0541 
0542 void KisImageConfig::setMaxNumberOfThreads(int value)
0543 {
0544     if (value == QThread::idealThreadCount()) {
0545         m_config.deleteEntry("maxNumberOfThreads");
0546     } else {
0547         m_config.writeEntry("maxNumberOfThreads", value);
0548     }
0549 }
0550 
0551 int KisImageConfig::frameRenderingClones(bool defaultValue) const
0552 {
0553     const int defaultClonesCount = qMax(1, maxNumberOfThreads(defaultValue) / 2);
0554     return defaultValue ? defaultClonesCount : m_config.readEntry("frameRenderingClones", defaultClonesCount);
0555 }
0556 
0557 void KisImageConfig::setFrameRenderingClones(int value)
0558 {
0559     m_config.writeEntry("frameRenderingClones", value);
0560 }
0561 
0562 int KisImageConfig::frameRenderingTimeout(bool defaultValue) const
0563 {
0564     const int defaultFrameRenderingTimeout = 30000; // 30 ms
0565     return defaultValue ? defaultFrameRenderingTimeout : m_config.readEntry("frameRenderingTimeout", defaultFrameRenderingTimeout);
0566 }
0567 
0568 void KisImageConfig::setFrameRenderingTimeout(int value)
0569 {
0570     m_config.writeEntry("frameRenderingTimeout", value);
0571 }
0572 
0573 int KisImageConfig::fpsLimit(bool defaultValue) const
0574 {
0575     int limit = defaultValue ? 100 : m_config.readEntry("fpsLimit", 100);
0576     return limit > 0 ? limit : 1;
0577 }
0578 
0579 void KisImageConfig::setFpsLimit(int value)
0580 {
0581     m_config.writeEntry("fpsLimit", value);
0582 }
0583 
0584 bool KisImageConfig::useOnDiskAnimationCacheSwapping(bool defaultValue) const
0585 {
0586     return defaultValue ? true : m_config.readEntry("useOnDiskAnimationCacheSwapping", true);
0587 }
0588 
0589 void KisImageConfig::setUseOnDiskAnimationCacheSwapping(bool value)
0590 {
0591     m_config.writeEntry("useOnDiskAnimationCacheSwapping", value);
0592 }
0593 
0594 QString KisImageConfig::animationCacheDir(bool defaultValue) const
0595 {
0596     return safelyGetWritableTempLocation("animation_cache", "animationCacheDir", defaultValue);
0597 }
0598 
0599 void KisImageConfig::setAnimationCacheDir(const QString &value)
0600 {
0601     m_config.writeEntry("animationCacheDir", value);
0602 }
0603 
0604 bool KisImageConfig::useAnimationCacheFrameSizeLimit(bool defaultValue) const
0605 {
0606     return defaultValue ? true : m_config.readEntry("useAnimationCacheFrameSizeLimit", true);
0607 }
0608 
0609 void KisImageConfig::setUseAnimationCacheFrameSizeLimit(bool value)
0610 {
0611     m_config.writeEntry("useAnimationCacheFrameSizeLimit", value);
0612 }
0613 
0614 int KisImageConfig::animationCacheFrameSizeLimit(bool defaultValue) const
0615 {
0616     return defaultValue ? 2500 : m_config.readEntry("animationCacheFrameSizeLimit", 2500);
0617 }
0618 
0619 void KisImageConfig::setAnimationCacheFrameSizeLimit(int value)
0620 {
0621     m_config.writeEntry("animationCacheFrameSizeLimit", value);
0622 }
0623 
0624 bool KisImageConfig::useAnimationCacheRegionOfInterest(bool defaultValue) const
0625 {
0626     return defaultValue ? true : m_config.readEntry("useAnimationCacheRegionOfInterest", true);
0627 }
0628 
0629 void KisImageConfig::setUseAnimationCacheRegionOfInterest(bool value)
0630 {
0631     m_config.writeEntry("useAnimationCacheRegionOfInterest", value);
0632 }
0633 
0634 qreal KisImageConfig::animationCacheRegionOfInterestMargin(bool defaultValue) const
0635 {
0636     return defaultValue ? 0.25 : m_config.readEntry("animationCacheRegionOfInterestMargin", 0.25);
0637 }
0638 
0639 void KisImageConfig::setAnimationCacheRegionOfInterestMargin(qreal value)
0640 {
0641     m_config.writeEntry("animationCacheRegionOfInterestMargin", value);
0642 }
0643 
0644 QColor KisImageConfig::selectionOverlayMaskColor(bool defaultValue) const
0645 {
0646     QColor def(255, 0, 0, 128);
0647     return (defaultValue ? def : m_config.readEntry("selectionOverlayMaskColor", def));
0648 }
0649 
0650 void KisImageConfig::setSelectionOverlayMaskColor(const QColor &color)
0651 {
0652     m_config.writeEntry("selectionOverlayMaskColor", color);
0653 }
0654 
0655 int KisImageConfig::maxBrushSize(bool defaultValue) const
0656 {
0657     return !defaultValue ? m_config.readEntry("maximumBrushSize", 1000) : 1000;
0658 }
0659 
0660 void KisImageConfig::setMaxBrushSize(int value)
0661 {
0662     m_config.writeEntry("maximumBrushSize", value);
0663 }
0664 
0665 int KisImageConfig::maxMaskingBrushSize() const
0666 {
0667     return qMin(15000, 3 * maxBrushSize());
0668 }
0669 
0670 QString KisImageConfig::exportConfigurationXML(const QString &exportConfigId, bool defaultValue) const
0671 {
0672     return (defaultValue ? QString() : m_config.readEntry("ExportConfiguration-" + exportConfigId, QString()));
0673 }
0674 
0675 bool KisImageConfig::hasExportConfiguration(const QString &exportConfigID)
0676 {
0677     return m_config.hasKey("ExportConfiguration-" + exportConfigID);
0678 }
0679 
0680 KisPropertiesConfigurationSP KisImageConfig::exportConfiguration(const QString &exportConfigId, bool defaultValue) const
0681 {
0682     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0683     const QString xmlData = exportConfigurationXML(exportConfigId, defaultValue);
0684     cfg->fromXML(xmlData);
0685     return cfg;
0686 }
0687 
0688 void KisImageConfig::setExportConfiguration(const QString &exportConfigId, KisPropertiesConfigurationSP properties)
0689 {
0690     const QString exportConfig = properties->toXML();
0691     QString configId = "ExportConfiguration-" + exportConfigId;
0692     m_config.writeEntry(configId, exportConfig);
0693 }
0694 
0695 void KisImageConfig::resetConfig()
0696 {
0697     KConfigGroup config = KSharedConfig::openConfig()->group(QString());
0698     config.deleteGroup();
0699 }