1 /*
2  *  Copyright (c) 2010 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "kis_image_config.h"
20 
21 #include <ksharedconfig.h>
22 
23 #include <KoConfig.h>
24 #include <KoColorProfile.h>
25 #include <KoColorSpaceRegistry.h>
26 #include <KoColorConversionTransformation.h>
27 
28 #include "kis_debug.h"
29 
30 #include <QThread>
31 #include <QApplication>
32 #include <QColor>
33 #include <QDir>
34 
35 #include "kis_global.h"
36 #include <cmath>
37 #include <QTemporaryFile>
38 
39 #ifdef Q_OS_MACOS
40 #include <errno.h>
41 #endif
42 
43 #ifdef Q_OS_FREEBSD
44 #include <sys/types.h>
45 #include <sys/sysctl.h>
46 #endif
47 
KisImageConfig(bool readOnly)48 KisImageConfig::KisImageConfig(bool readOnly)
49     : m_config(KSharedConfig::openConfig()->group(QString()))
50     , m_readOnly(readOnly)
51 {
52     if (!readOnly) {
53         KIS_SAFE_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
54     }
55 #ifdef Q_OS_MACOS
56     // clear /var/folders/ swap path set by old broken Krita swap implementation in order to use new default swap dir.
57     QString swap = m_config.readEntry("swaplocation", "");
58     if (swap.startsWith("/var/folders/")) {
59         m_config.deleteEntry("swaplocation");
60     }
61 #endif
62 }
63 
~KisImageConfig()64 KisImageConfig::~KisImageConfig()
65 {
66     if (m_readOnly) return;
67 
68     if (qApp->thread() != QThread::currentThread()) {
69         dbgKrita << "KisImageConfig: requested config synchronization from nonGUI thread! Called from" << kisBacktrace();
70         return;
71     }
72 
73     m_config.sync();
74 }
75 
enableProgressReporting(bool requestDefault) const76 bool KisImageConfig::enableProgressReporting(bool requestDefault) const
77 {
78     return !requestDefault ?
79         m_config.readEntry("enableProgressReporting", true) : true;
80 }
81 
setEnableProgressReporting(bool value)82 void KisImageConfig::setEnableProgressReporting(bool value)
83 {
84     m_config.writeEntry("enableProgressReporting", value);
85 }
86 
enablePerfLog(bool requestDefault) const87 bool KisImageConfig::enablePerfLog(bool requestDefault) const
88 {
89     return !requestDefault ?
90         m_config.readEntry("enablePerfLog", false) :false;
91 }
92 
setEnablePerfLog(bool value)93 void KisImageConfig::setEnablePerfLog(bool value)
94 {
95     m_config.writeEntry("enablePerfLog", value);
96 }
97 
transformMaskOffBoundsReadArea() const98 qreal KisImageConfig::transformMaskOffBoundsReadArea() const
99 {
100     return m_config.readEntry("transformMaskOffBoundsReadArea", 0.5);
101 }
102 
updatePatchHeight() const103 int KisImageConfig::updatePatchHeight() const
104 {
105     int patchHeight = m_config.readEntry("updatePatchHeight", 512);
106     if (patchHeight <= 0) return 512;
107     return patchHeight;
108 }
109 
setUpdatePatchHeight(int value)110 void KisImageConfig::setUpdatePatchHeight(int value)
111 {
112     m_config.writeEntry("updatePatchHeight", value);
113 }
114 
updatePatchWidth() const115 int KisImageConfig::updatePatchWidth() const
116 {
117     int patchWidth = m_config.readEntry("updatePatchWidth", 512);
118     if (patchWidth <= 0) return 512;
119     return patchWidth;
120 }
121 
setUpdatePatchWidth(int value)122 void KisImageConfig::setUpdatePatchWidth(int value)
123 {
124     m_config.writeEntry("updatePatchWidth", value);
125 }
126 
maxCollectAlpha() const127 qreal KisImageConfig::maxCollectAlpha() const
128 {
129     return m_config.readEntry("maxCollectAlpha", 2.5);
130 }
131 
maxMergeAlpha() const132 qreal KisImageConfig::maxMergeAlpha() const
133 {
134     return m_config.readEntry("maxMergeAlpha", 1.);
135 }
136 
maxMergeCollectAlpha() const137 qreal KisImageConfig::maxMergeCollectAlpha() const
138 {
139     return m_config.readEntry("maxMergeCollectAlpha", 1.5);
140 }
141 
schedulerBalancingRatio() const142 qreal KisImageConfig::schedulerBalancingRatio() const
143 {
144     /**
145      * updates-queue-size / strokes-queue-size
146      */
147     return m_config.readEntry("schedulerBalancingRatio", 100.);
148 }
149 
setSchedulerBalancingRatio(qreal value)150 void KisImageConfig::setSchedulerBalancingRatio(qreal value)
151 {
152     m_config.writeEntry("schedulerBalancingRatio", value);
153 }
154 
maxSwapSize(bool requestDefault) const155 int KisImageConfig::maxSwapSize(bool requestDefault) const
156 {
157     return !requestDefault ?
158         m_config.readEntry("maxSwapSize", 4096) : 4096; // in MiB
159 }
160 
setMaxSwapSize(int value)161 void KisImageConfig::setMaxSwapSize(int value)
162 {
163     m_config.writeEntry("maxSwapSize", value);
164 }
165 
swapSlabSize() const166 int KisImageConfig::swapSlabSize() const
167 {
168     return m_config.readEntry("swapSlabSize", 64); // in MiB
169 }
170 
setSwapSlabSize(int value)171 void KisImageConfig::setSwapSlabSize(int value)
172 {
173     m_config.writeEntry("swapSlabSize", value);
174 }
175 
swapWindowSize() const176 int KisImageConfig::swapWindowSize() const
177 {
178     return m_config.readEntry("swapWindowSize", 16); // in MiB
179 }
180 
setSwapWindowSize(int value)181 void KisImageConfig::setSwapWindowSize(int value)
182 {
183     m_config.writeEntry("swapWindowSize", value);
184 }
185 
tilesHardLimit() const186 int KisImageConfig::tilesHardLimit() const
187 {
188     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
189     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
190 
191     return totalRAM() * hp * (1 - pp);
192 }
193 
tilesSoftLimit() const194 int KisImageConfig::tilesSoftLimit() const
195 {
196     qreal sp = qreal(memorySoftLimitPercent()) / 100.0;
197 
198     return tilesHardLimit() * sp;
199 }
200 
poolLimit() const201 int KisImageConfig::poolLimit() const
202 {
203     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
204     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
205 
206     return totalRAM() * hp * pp;
207 }
208 
memoryHardLimitPercent(bool requestDefault) const209 qreal KisImageConfig::memoryHardLimitPercent(bool requestDefault) const
210 {
211     return !requestDefault ?
212         m_config.readEntry("memoryHardLimitPercent", 50.) : 50.;
213 }
214 
setMemoryHardLimitPercent(qreal value)215 void KisImageConfig::setMemoryHardLimitPercent(qreal value)
216 {
217     m_config.writeEntry("memoryHardLimitPercent", value);
218 }
219 
memorySoftLimitPercent(bool requestDefault) const220 qreal KisImageConfig::memorySoftLimitPercent(bool requestDefault) const
221 {
222     return !requestDefault ?
223         m_config.readEntry("memorySoftLimitPercent", 2.) : 2.;
224 }
225 
setMemorySoftLimitPercent(qreal value)226 void KisImageConfig::setMemorySoftLimitPercent(qreal value)
227 {
228     m_config.writeEntry("memorySoftLimitPercent", value);
229 }
230 
memoryPoolLimitPercent(bool requestDefault) const231 qreal KisImageConfig::memoryPoolLimitPercent(bool requestDefault) const
232 {
233     return !requestDefault ?
234         m_config.readEntry("memoryPoolLimitPercent", 0.0) : 0.0;
235 }
236 
setMemoryPoolLimitPercent(qreal value)237 void KisImageConfig::setMemoryPoolLimitPercent(qreal value)
238 {
239     m_config.writeEntry("memoryPoolLimitPercent", value);
240 }
241 
safelyGetWritableTempLocation(const QString & suffix,const QString & configKey,bool requestDefault) const242 QString KisImageConfig::safelyGetWritableTempLocation(const QString &suffix, const QString &configKey, bool requestDefault) const
243 {
244 #ifdef Q_OS_MACOS
245     // On OSX, QDir::tempPath() gives us a folder we cannot reply upon (usually
246     // something like /var/folders/.../...) and that will have vanished when we
247     // try to create the tmp file in KisMemoryWindow::KisMemoryWindow using
248     // swapFileTemplate. thus, we just pick the home folder if swapDir does not
249     // tell us otherwise.
250 
251     // the other option here would be to use a "garbled name" temp file (i.e. no name
252     // KRITA_SWAP_FILE_XXXXXX) in an obscure /var/folders place, which is not
253     // nice to the user. having a clearly named swap file in the home folder is
254     // much nicer to Krita's users.
255 
256     // furthermore, this is just a default and swapDir can always be configured
257     // to another location.
258 
259     QString swap = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/' + suffix;
260 #else
261     Q_UNUSED(suffix);
262     QString swap = QDir::tempPath();
263 #endif
264     if (requestDefault) {
265        return swap;
266     }
267     const QString configuredSwap = m_config.readEntry(configKey, swap);
268     if (!configuredSwap.isEmpty()) {
269         swap = configuredSwap;
270     }
271 
272     QString chosenLocation;
273     QStringList proposedSwapLocations;
274     proposedSwapLocations << swap;
275     proposedSwapLocations << QDir::tempPath();
276     proposedSwapLocations << QDir::homePath();
277 
278     Q_FOREACH (const QString location, proposedSwapLocations) {
279         if (!QFileInfo(location).isWritable()) continue;
280 
281         /**
282          * On NTFS, isWritable() doesn't check for attributes due to performance
283          * reasons, so we should try it in a brute-force way...
284          * (yes, there is a hacky-global-variable workaround, but let's be safe)
285          */
286         QTemporaryFile tempFile;
287         tempFile.setFileTemplate(location + '/' + "krita_test_swap_location");
288         if (tempFile.open() && !tempFile.fileName().isEmpty()) {
289             chosenLocation = location;
290             break;
291         }
292     }
293 
294     if (chosenLocation.isEmpty()) {
295         qCritical() << "CRITICAL: no writable location for a swap file found! Tried the following paths:" << proposedSwapLocations;
296         qCritical() << "CRITICAL: hope I don't crash...";
297         chosenLocation = swap;
298     }
299 
300     if (chosenLocation != swap) {
301         qWarning() << "WARNING: configured swap location is not writable, using a fall-back location" << swap << "->" << chosenLocation;
302     }
303 
304     return chosenLocation;
305 }
306 
307 
swapDir(bool requestDefault)308 QString KisImageConfig::swapDir(bool requestDefault)
309 {
310     return safelyGetWritableTempLocation("swap", "swaplocation", requestDefault);
311 }
312 
setSwapDir(const QString & swapDir)313 void KisImageConfig::setSwapDir(const QString &swapDir)
314 {
315     m_config.writeEntry("swaplocation", swapDir);
316 }
317 
numberOfOnionSkins() const318 int KisImageConfig::numberOfOnionSkins() const
319 {
320     return m_config.readEntry("numberOfOnionSkins", 10);
321 }
322 
setNumberOfOnionSkins(int value)323 void KisImageConfig::setNumberOfOnionSkins(int value)
324 {
325     m_config.writeEntry("numberOfOnionSkins", value);
326 }
327 
onionSkinTintFactor() const328 int KisImageConfig::onionSkinTintFactor() const
329 {
330     return m_config.readEntry("onionSkinTintFactor", 192);
331 }
332 
setOnionSkinTintFactor(int value)333 void KisImageConfig::setOnionSkinTintFactor(int value)
334 {
335     m_config.writeEntry("onionSkinTintFactor", value);
336 }
337 
onionSkinOpacity(int offset) const338 int KisImageConfig::onionSkinOpacity(int offset) const
339 {
340     int value = m_config.readEntry("onionSkinOpacity_" + QString::number(offset), -1);
341 
342     if (value < 0) {
343         const int num = numberOfOnionSkins();
344         const qreal dx = qreal(qAbs(offset)) / num;
345         value = 0.7 * exp(-pow2(dx) / 0.5) * 255;
346     }
347 
348     return value;
349 }
350 
setOnionSkinOpacity(int offset,int value)351 void KisImageConfig::setOnionSkinOpacity(int offset, int value)
352 {
353     m_config.writeEntry("onionSkinOpacity_" + QString::number(offset), value);
354 }
355 
onionSkinState(int offset) const356 bool KisImageConfig::onionSkinState(int offset) const
357 {
358     bool enableByDefault = (qAbs(offset) <= 2);
359     return m_config.readEntry("onionSkinState_" + QString::number(offset), enableByDefault);
360 }
361 
setOnionSkinState(int offset,bool value)362 void KisImageConfig::setOnionSkinState(int offset, bool value)
363 {
364     m_config.writeEntry("onionSkinState_" + QString::number(offset), value);
365 }
366 
onionSkinTintColorBackward() const367 QColor KisImageConfig::onionSkinTintColorBackward() const
368 {
369     return m_config.readEntry("onionSkinTintColorBackward", QColor(Qt::red));
370 }
371 
setOnionSkinTintColorBackward(const QColor & value)372 void KisImageConfig::setOnionSkinTintColorBackward(const QColor &value)
373 {
374     m_config.writeEntry("onionSkinTintColorBackward", value);
375 }
376 
onionSkinTintColorForward() const377 QColor KisImageConfig::onionSkinTintColorForward() const
378 {
379     return m_config.readEntry("oninSkinTintColorForward", QColor(Qt::green));
380 }
381 
setOnionSkinTintColorForward(const QColor & value)382 void KisImageConfig::setOnionSkinTintColorForward(const QColor &value)
383 {
384     m_config.writeEntry("oninSkinTintColorForward", value);
385 }
386 
lazyFrameCreationEnabled(bool requestDefault) const387 bool KisImageConfig::lazyFrameCreationEnabled(bool requestDefault) const
388 {
389     return !requestDefault ?
390         m_config.readEntry("lazyFrameCreationEnabled", true) : true;
391 }
392 
setLazyFrameCreationEnabled(bool value)393 void KisImageConfig::setLazyFrameCreationEnabled(bool value)
394 {
395     m_config.writeEntry("lazyFrameCreationEnabled", value);
396 }
397 
398 
399 #if defined Q_OS_LINUX
400 #include <sys/sysinfo.h>
401 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
402 #include <sys/sysctl.h>
403 #elif defined Q_OS_WIN
404 #include <windows.h>
405 #elif defined Q_OS_MACOS
406 #include <sys/types.h>
407 #include <sys/sysctl.h>
408 #endif
409 
totalRAM()410 int KisImageConfig::totalRAM()
411 {
412     // let's think that default memory size is 1000MiB
413     int totalMemory = 1000; // MiB
414     int error = 1;
415 
416 #if defined Q_OS_LINUX
417     struct sysinfo info;
418 
419     error = sysinfo(&info);
420     if(!error) {
421         totalMemory = info.totalram * info.mem_unit / (1UL << 20);
422     }
423 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
424     u_long physmem;
425 #   if defined HW_PHYSMEM64 // NetBSD only
426     int mib[] = {CTL_HW, HW_PHYSMEM64};
427 #   else
428     int mib[] = {CTL_HW, HW_PHYSMEM};
429 #   endif
430     size_t len = sizeof(physmem);
431 
432     error = sysctl(mib, 2, &physmem, &len, 0, 0);
433     if(!error) {
434         totalMemory = physmem >> 20;
435     }
436 #elif defined Q_OS_WIN
437     MEMORYSTATUSEX status;
438     status.dwLength = sizeof(status);
439     error  = !GlobalMemoryStatusEx(&status);
440 
441     if (!error) {
442         totalMemory = status.ullTotalPhys >> 20;
443     }
444 
445     // For 32 bit windows, the total memory available is at max the 2GB per process memory limit.
446 #   if defined ENV32BIT
447     totalMemory = qMin(totalMemory, 2000);
448 #   endif
449 #elif defined Q_OS_MACOS
450     int mib[2] = { CTL_HW, HW_MEMSIZE };
451     u_int namelen = sizeof(mib) / sizeof(mib[0]);
452     uint64_t size;
453     size_t len = sizeof(size);
454 
455     errno = 0;
456     if (sysctl(mib, namelen, &size, &len, 0, 0) >= 0) {
457         totalMemory = size >> 20;
458         error = 0;
459     }
460     else {
461         dbgKrita << "sysctl(\"hw.memsize\") raised error" << strerror(errno);
462     }
463 #endif
464 
465     if (error) {
466         warnKrita << "Cannot get the size of your RAM. Using 1 GiB by default.";
467     }
468 
469     return totalMemory;
470 }
471 
showAdditionalOnionSkinsSettings(bool requestDefault) const472 bool KisImageConfig::showAdditionalOnionSkinsSettings(bool requestDefault) const
473 {
474     return !requestDefault ?
475         m_config.readEntry("showAdditionalOnionSkinsSettings", true) : true;
476 }
477 
setShowAdditionalOnionSkinsSettings(bool value)478 void KisImageConfig::setShowAdditionalOnionSkinsSettings(bool value)
479 {
480     m_config.writeEntry("showAdditionalOnionSkinsSettings", value);
481 }
482 
defaultFrameColorLabel() const483 int KisImageConfig::defaultFrameColorLabel() const
484 {
485     return m_config.readEntry("defaultFrameColorLabel", 0);
486 }
487 
setDefaultFrameColorLabel(int label)488 void KisImageConfig::setDefaultFrameColorLabel(int label)
489 {
490     m_config.writeEntry("defaultFrameColorLabel", label);
491 }
492 
defaultProofingconfiguration()493 KisProofingConfigurationSP KisImageConfig::defaultProofingconfiguration()
494 {
495     KisProofingConfiguration *proofingConfig= new KisProofingConfiguration();
496     proofingConfig->proofingProfile = m_config.readEntry("defaultProofingProfileName", "Chemical proof");
497     proofingConfig->proofingModel = m_config.readEntry("defaultProofingProfileModel", "CMYKA");
498     proofingConfig->proofingDepth = m_config.readEntry("defaultProofingProfileDepth", "U8");
499     proofingConfig->intent = (KoColorConversionTransformation::Intent)m_config.readEntry("defaultProofingProfileIntent", 3);
500     if (m_config.readEntry("defaultProofingBlackpointCompensation", true)) {
501         proofingConfig->conversionFlags  |= KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
502     } else {
503         proofingConfig->conversionFlags  = proofingConfig->conversionFlags & ~KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
504     }
505     QColor def(Qt::green);
506     m_config.readEntry("defaultProofingGamutwarning", def);
507     KoColor col(KoColorSpaceRegistry::instance()->rgb8());
508     col.fromQColor(def);
509     col.setOpacity(1.0);
510     proofingConfig->warningColor = col;
511     proofingConfig->adaptationState = (double)m_config.readEntry("defaultProofingAdaptationState", 1.0);
512     return toQShared(proofingConfig);
513 }
514 
setDefaultProofingConfig(const KoColorSpace * proofingSpace,int proofingIntent,bool blackPointCompensation,KoColor warningColor,double adaptationState)515 void KisImageConfig::setDefaultProofingConfig(const KoColorSpace *proofingSpace, int proofingIntent, bool blackPointCompensation, KoColor warningColor, double adaptationState)
516 {
517     m_config.writeEntry("defaultProofingProfileName", proofingSpace->profile()->name());
518     m_config.writeEntry("defaultProofingProfileModel", proofingSpace->colorModelId().id());
519     m_config.writeEntry("defaultProofingProfileDepth", proofingSpace->colorDepthId().id());
520     m_config.writeEntry("defaultProofingProfileIntent", proofingIntent);
521     m_config.writeEntry("defaultProofingBlackpointCompensation", blackPointCompensation);
522     QColor c;
523     c = warningColor.toQColor();
524     m_config.writeEntry("defaultProofingGamutwarning", c);
525     m_config.writeEntry("defaultProofingAdaptationState",adaptationState);
526 }
527 
useLodForColorizeMask(bool requestDefault) const528 bool KisImageConfig::useLodForColorizeMask(bool requestDefault) const
529 {
530     return !requestDefault ?
531         m_config.readEntry("useLodForColorizeMask", false) : false;
532 }
533 
setUseLodForColorizeMask(bool value)534 void KisImageConfig::setUseLodForColorizeMask(bool value)
535 {
536     m_config.writeEntry("useLodForColorizeMask", value);
537 }
538 
maxNumberOfThreads(bool defaultValue) const539 int KisImageConfig::maxNumberOfThreads(bool defaultValue) const
540 {
541     return (defaultValue ? QThread::idealThreadCount() : m_config.readEntry("maxNumberOfThreads", QThread::idealThreadCount()));
542 }
543 
setMaxNumberOfThreads(int value)544 void KisImageConfig::setMaxNumberOfThreads(int value)
545 {
546     if (value == QThread::idealThreadCount()) {
547         m_config.deleteEntry("maxNumberOfThreads");
548     } else {
549         m_config.writeEntry("maxNumberOfThreads", value);
550     }
551 }
552 
frameRenderingClones(bool defaultValue) const553 int KisImageConfig::frameRenderingClones(bool defaultValue) const
554 {
555     const int defaultClonesCount = qMax(1, maxNumberOfThreads(defaultValue) / 2);
556     return defaultValue ? defaultClonesCount : m_config.readEntry("frameRenderingClones", defaultClonesCount);
557 }
558 
setFrameRenderingClones(int value)559 void KisImageConfig::setFrameRenderingClones(int value)
560 {
561     m_config.writeEntry("frameRenderingClones", value);
562 }
563 
fpsLimit(bool defaultValue) const564 int KisImageConfig::fpsLimit(bool defaultValue) const
565 {
566     int limit = defaultValue ? 100 : m_config.readEntry("fpsLimit", 100);
567     return limit > 0 ? limit : 1;
568 }
569 
setFpsLimit(int value)570 void KisImageConfig::setFpsLimit(int value)
571 {
572     m_config.writeEntry("fpsLimit", value);
573 }
574 
useOnDiskAnimationCacheSwapping(bool defaultValue) const575 bool KisImageConfig::useOnDiskAnimationCacheSwapping(bool defaultValue) const
576 {
577     return defaultValue ? true : m_config.readEntry("useOnDiskAnimationCacheSwapping", true);
578 }
579 
setUseOnDiskAnimationCacheSwapping(bool value)580 void KisImageConfig::setUseOnDiskAnimationCacheSwapping(bool value)
581 {
582     m_config.writeEntry("useOnDiskAnimationCacheSwapping", value);
583 }
584 
animationCacheDir(bool defaultValue) const585 QString KisImageConfig::animationCacheDir(bool defaultValue) const
586 {
587     return safelyGetWritableTempLocation("animation_cache", "animationCacheDir", defaultValue);
588 }
589 
setAnimationCacheDir(const QString & value)590 void KisImageConfig::setAnimationCacheDir(const QString &value)
591 {
592     m_config.writeEntry("animationCacheDir", value);
593 }
594 
useAnimationCacheFrameSizeLimit(bool defaultValue) const595 bool KisImageConfig::useAnimationCacheFrameSizeLimit(bool defaultValue) const
596 {
597     return defaultValue ? true : m_config.readEntry("useAnimationCacheFrameSizeLimit", true);
598 }
599 
setUseAnimationCacheFrameSizeLimit(bool value)600 void KisImageConfig::setUseAnimationCacheFrameSizeLimit(bool value)
601 {
602     m_config.writeEntry("useAnimationCacheFrameSizeLimit", value);
603 }
604 
animationCacheFrameSizeLimit(bool defaultValue) const605 int KisImageConfig::animationCacheFrameSizeLimit(bool defaultValue) const
606 {
607     return defaultValue ? 2500 : m_config.readEntry("animationCacheFrameSizeLimit", 2500);
608 }
609 
setAnimationCacheFrameSizeLimit(int value)610 void KisImageConfig::setAnimationCacheFrameSizeLimit(int value)
611 {
612     m_config.writeEntry("animationCacheFrameSizeLimit", value);
613 }
614 
useAnimationCacheRegionOfInterest(bool defaultValue) const615 bool KisImageConfig::useAnimationCacheRegionOfInterest(bool defaultValue) const
616 {
617     return defaultValue ? true : m_config.readEntry("useAnimationCacheRegionOfInterest", true);
618 }
619 
setUseAnimationCacheRegionOfInterest(bool value)620 void KisImageConfig::setUseAnimationCacheRegionOfInterest(bool value)
621 {
622     m_config.writeEntry("useAnimationCacheRegionOfInterest", value);
623 }
624 
animationCacheRegionOfInterestMargin(bool defaultValue) const625 qreal KisImageConfig::animationCacheRegionOfInterestMargin(bool defaultValue) const
626 {
627     return defaultValue ? 0.25 : m_config.readEntry("animationCacheRegionOfInterestMargin", 0.25);
628 }
629 
setAnimationCacheRegionOfInterestMargin(qreal value)630 void KisImageConfig::setAnimationCacheRegionOfInterestMargin(qreal value)
631 {
632     m_config.writeEntry("animationCacheRegionOfInterestMargin", value);
633 }
634 
selectionOverlayMaskColor(bool defaultValue) const635 QColor KisImageConfig::selectionOverlayMaskColor(bool defaultValue) const
636 {
637     QColor def(255, 0, 0, 128);
638     return (defaultValue ? def : m_config.readEntry("selectionOverlayMaskColor", def));
639 }
640 
setSelectionOverlayMaskColor(const QColor & color)641 void KisImageConfig::setSelectionOverlayMaskColor(const QColor &color)
642 {
643     m_config.writeEntry("selectionOverlayMaskColor", color);
644 }
645 
resetConfig()646 void KisImageConfig::resetConfig()
647 {
648     KConfigGroup config = KSharedConfig::openConfig()->group(QString());
649     config.deleteGroup();
650 }
651