1
2
3 #include "toonz/preferences.h"
4
5 // TnzLib includes
6 #include "toonz/tscenehandle.h"
7 #include "toonz/toonzscene.h"
8 #include "toonz/toonzfolders.h"
9 #include "toonz/tcamera.h"
10 #include "toonz/txshleveltypes.h"
11
12 // TnzBase includes
13 #include "tenv.h"
14 #include "tunit.h"
15
16 // TnzCore includes
17 #include "tsystem.h"
18 #include "tconvert.h"
19 #include "tundo.h"
20 #include "tbigmemorymanager.h"
21 #include "tfilepath.h"
22 #include "timage_io.h"
23
24 // Qt includes
25 #include <QSettings>
26 #include <QStringList>
27 #include <QAction>
28 #include <QColor>
29 #include <QTextStream>
30
31 // boost includes
32 #include <boost/bind.hpp>
33
34 //**********************************************************************************
35 // Local namespace stuff
36 //**********************************************************************************
37
38 namespace {
39
40 typedef Preferences::LevelFormat LevelFormat;
41 typedef std::vector<LevelFormat> LevelFormatVector;
42
43 //-----------------------------------------------------------------
44
45 const char *s_levelFormats = "levelFormats";
46
47 const char *s_name = "name", *s_regexp = "regexp", *s_priority = "priority";
48
49 const char *s_dpiPolicy = "dpiPolicy", *s_dpi = "dpi",
50 *s_subsampling = "subsampling", *s_antialias = "antialias",
51 *s_premultiply = "premultiply", *s_whiteTransp = "whiteTransp";
52
53 //=================================================================
54
colorToString(const QColor & color)55 inline QString colorToString(const QColor &color) {
56 return QString("%1 %2 %3 %4")
57 .arg(color.red())
58 .arg(color.green())
59 .arg(color.blue())
60 .arg(color.alpha());
61 }
62
stringToColor(const QString & str)63 inline QColor stringToColor(const QString &str) {
64 QStringList values = str.split(' ');
65 return QColor(values[0].toInt(), values[1].toInt(), values[2].toInt(),
66 values[3].toInt());
67 }
68
colorToTPixel(const QColor & color)69 inline TPixel colorToTPixel(const QColor &color) {
70 return TPixel(color.red(), color.green(), color.blue(), color.alpha());
71 }
72
73 //-----------------------------------------------------------------
74
setCurrentUnits(std::string measureName,std::string units)75 static void setCurrentUnits(std::string measureName, std::string units) {
76 TMeasure *m = TMeasureManager::instance()->get(measureName);
77 if (!m) return;
78 TUnit *u = m->getUnit(::to_wstring(units));
79 if (!u) return;
80 m->setCurrentUnit(u);
81 }
82
83 //-----------------------------------------------------------------
84
formatLess(const Preferences::LevelFormat & a,const Preferences::LevelFormat & b)85 inline bool formatLess(const Preferences::LevelFormat &a,
86 const Preferences::LevelFormat &b) {
87 return (
88 a.m_priority > b.m_priority // Observe '>' used here - we want inverse
89 || (!(b.m_priority >
90 a.m_priority) // sorting on priority, higher priorities come first
91 && a.m_name < b.m_name));
92 }
93
94 //=================================================================
95
getDefaultLevelFormats(LevelFormatVector & lfv)96 void getDefaultLevelFormats(LevelFormatVector &lfv) {
97 lfv.resize(3);
98 {
99 LevelFormat &lf = lfv[0];
100
101 lf.m_name = Preferences::tr("Retas Level Format");
102 lf.m_pathFormat = QRegExp(".+[0-9]{4,4}\\.tga", Qt::CaseInsensitive);
103 lf.m_options.m_whiteTransp = true;
104 lf.m_options.m_antialias = 70;
105
106 // for all PSD files, set the premultiply options to layers
107 lfv[1].m_name = Preferences::tr("Adobe Photoshop");
108 lfv[1].m_pathFormat = QRegExp("..*\\.psd", Qt::CaseInsensitive);
109 lfv[1].m_options.m_premultiply = true;
110
111 // for all PNG files, set premultiply by default
112 // UPDATE : from V1.5, PNG images are premultiplied on loading
113 // lfv[2].m_name = Preferences::tr("PNG");
114 // lfv[2].m_pathFormat = QRegExp("..*\\.png",
115 // Qt::CaseInsensitive); lfv[2].m_options.m_premultiply = true;
116 }
117 }
118
119 //=================================================================
120
setValue(QSettings & settings,const LevelOptions & lo)121 void setValue(QSettings &settings, const LevelOptions &lo) {
122 settings.setValue(s_dpiPolicy, int(lo.m_dpiPolicy));
123 settings.setValue(s_dpi, lo.m_dpi);
124 settings.setValue(s_subsampling, lo.m_subsampling);
125 settings.setValue(s_antialias, lo.m_antialias);
126 settings.setValue(s_premultiply, int(lo.m_premultiply));
127 settings.setValue(s_whiteTransp, int(lo.m_whiteTransp));
128 }
129
130 //-----------------------------------------------------------------
131
getValue(const QSettings & settings,LevelOptions & lo)132 void getValue(const QSettings &settings, LevelOptions &lo) {
133 int dpiPolicy = settings.value(s_dpiPolicy, int(lo.m_dpiPolicy)).toInt();
134 lo.m_dpiPolicy = LevelOptions::DpiPolicy(dpiPolicy);
135 lo.m_dpi = settings.value(s_dpi, lo.m_dpi).toDouble();
136 lo.m_subsampling = settings.value(s_subsampling, lo.m_subsampling).toInt();
137 lo.m_antialias = settings.value(s_antialias, lo.m_antialias).toInt();
138 lo.m_premultiply =
139 (settings.value(s_premultiply, lo.m_premultiply).toInt() != 0);
140 lo.m_whiteTransp =
141 (settings.value(s_whiteTransp, lo.m_whiteTransp).toInt() != 0);
142 }
143
144 //-----------------------------------------------------------------
145
setValue(QSettings & settings,const LevelFormat & lf)146 void setValue(QSettings &settings, const LevelFormat &lf) {
147 settings.setValue(s_name, lf.m_name);
148 settings.setValue(s_regexp, lf.m_pathFormat.pattern());
149 settings.setValue(s_priority, lf.m_priority);
150 setValue(settings, lf.m_options);
151 }
152
153 //-----------------------------------------------------------------
154
getValue(const QSettings & settings,LevelFormat & lf)155 void getValue(const QSettings &settings, LevelFormat &lf) {
156 lf.m_name = settings.value(s_name, lf.m_name).toString();
157 lf.m_pathFormat =
158 QRegExp(settings.value(s_regexp, lf.m_pathFormat).toString(),
159 Qt::CaseInsensitive);
160 lf.m_priority = settings.value(s_priority, lf.m_priority).toInt();
161 getValue(settings, lf.m_options);
162 }
163
164 //-----------------------------------------------------------------
165
_setValue(QSettings & settings,const LevelFormatVector & lfv)166 void _setValue(QSettings &settings, const LevelFormatVector &lfv) {
167 int lf, lfCount = int(lfv.size());
168
169 settings.remove(s_levelFormats);
170
171 settings.beginWriteArray(s_levelFormats, lfCount);
172 {
173 for (lf = 0; lf != lfCount; ++lf) {
174 settings.setArrayIndex(lf);
175 setValue(settings, lfv[lf]);
176 }
177 }
178 settings.endArray();
179 }
180
181 //-----------------------------------------------------------------
182
getValue(QSettings & settings,LevelFormatVector & lfv)183 void getValue(QSettings &settings,
184 LevelFormatVector &lfv) // Why does QSettings' interface require
185 { // non-const access on reading arrays/groups?
186 if (!settings.childGroups().contains(s_levelFormats))
187 return; // Default is no level formats - use builtins
188
189 int lfCount = settings.beginReadArray(s_levelFormats); // lfCount could be 0
190 lfv.resize(lfCount);
191
192 for (int lf = 0; lf != lfCount; ++lf) {
193 settings.setArrayIndex(lf);
194 getValue(settings, lfv[lf]);
195 }
196 settings.endArray();
197
198 // from OT V1.5, PNG images are premultiplied on loading.
199 // Leaving the premultiply option will cause unwanted double operation.
200 // So, check the loaded options and modify it "silently".
201 bool changed = false;
202 LevelFormatVector::iterator it = lfv.begin();
203 while (it != lfv.end()) {
204 if ((*it).m_name == Preferences::tr("PNG") &&
205 (*it).m_pathFormat == QRegExp("..*\\.png", Qt::CaseInsensitive) &&
206 (*it).m_options.m_premultiply == true) {
207 LevelOptions defaultValue;
208 defaultValue.m_premultiply = true;
209 // if other parameters are the same as deafault, just erase the item
210 if ((*it).m_options == defaultValue) it = lfv.erase(it);
211 // if there are some adjustments by user, then disable only premultiply
212 // option
213 else {
214 (*it).m_options.m_premultiply = false;
215 ++it;
216 }
217 changed = true;
218 } else
219 ++it;
220 }
221 // overwrite the setting
222 if (changed) _setValue(settings, lfv);
223 }
224
225 } // namespace
226
227 //**********************************************************************************
228 // Preferences::LevelFormat implementation
229 //**********************************************************************************
230
matches(const TFilePath & fp) const231 bool Preferences::LevelFormat::matches(const TFilePath &fp) const {
232 return m_pathFormat.exactMatch(fp.getQString());
233 }
234
235 //**********************************************************************************
236 // Preferences implementation
237 //**********************************************************************************
238
Preferences()239 Preferences::Preferences() {
240 // load preference file
241 TFilePath layoutDir = ToonzFolder::getMyModuleDir();
242 TFilePath prefPath = layoutDir + TFilePath("preferences.ini");
243 // In case the personal settings is not exist (for new users)
244 if (!TFileStatus(prefPath).doesExist()) {
245 TFilePath templatePath =
246 ToonzFolder::getTemplateModuleDir() + TFilePath("preferences.ini");
247 // If there is the template, copy it to the personal one
248 if (TFileStatus(templatePath).doesExist())
249 TSystem::copyFile(prefPath, templatePath);
250 }
251 m_settings.reset(new QSettings(
252 QString::fromStdWString(prefPath.getWideString()), QSettings::IniFormat));
253
254 initializeOptions();
255
256 definePreferenceItems();
257 // resolve compatibility for deprecated items
258 resolveCompatibility();
259
260 // initialize environment based on loaded preferences
261 setUnits();
262 setCameraUnits();
263 setUndoMemorySize();
264
265 // Load level formats
266 getDefaultLevelFormats(m_levelFormats);
267 getValue(*m_settings, m_levelFormats);
268 std::sort(m_levelFormats.begin(),
269 m_levelFormats.end(), // Format sorting must be
270 formatLess); // enforced
271
272 if (m_roomMaps.key(getStringValue(CurrentRoomChoice), -1) == -1) {
273 assert(!m_roomMaps.isEmpty());
274 setValue(CurrentRoomChoice, m_roomMaps[0]);
275 }
276
277 if (!m_styleSheetList.contains(getStringValue(CurrentStyleSheetName)))
278 setValue(CurrentStyleSheetName, "Default");
279
280 if (!m_languageList.contains(getStringValue(CurrentLanguageName)))
281 setValue(CurrentLanguageName, "English");
282
283 TImageWriter::setBackgroundColor(getColorValue(rasterBackgroundColor));
284 }
285
286 //-----------------------------------------------------------------
287
~Preferences()288 Preferences::~Preferences() {
289 // DO NOT REMOVE
290 }
291
292 //-----------------------------------------------------------------
293
instance()294 Preferences *Preferences::instance() {
295 static Preferences _instance;
296 return &_instance;
297 }
298
299 //-----------------------------------------------------------------
300 // load and initialize options for languages, styles and rooms
301
initializeOptions()302 void Preferences::initializeOptions() {
303 // load languages
304 TFilePath lang_path = TEnv::getConfigDir() + "loc";
305 TFilePathSet lang_fpset;
306 m_languageList.append("English");
307 // m_currentLanguage=0;
308 try {
309 TFileStatus langPathFs(lang_path);
310
311 if (langPathFs.doesExist() && langPathFs.isDirectory()) {
312 TSystem::readDirectory(lang_fpset, lang_path, true, false);
313 }
314
315 int i = 0;
316 for (auto const &newPath : lang_fpset) {
317 ++i;
318 if (newPath == lang_path) continue;
319 if (TFileStatus(newPath).isDirectory()) {
320 QString string = QString::fromStdWString(newPath.getWideName());
321 m_languageList.append(string);
322 }
323 }
324 } catch (...) {
325 }
326
327 // load styles
328 TFilePath path(TEnv::getConfigDir() + "qss");
329 TFilePathSet fpset;
330 try {
331 TSystem::readDirectory(fpset, path, true, false);
332 int i = -1;
333 for (auto const &newPath : fpset) {
334 ++i;
335 if (newPath == path) continue;
336 QString fpName = QString::fromStdWString(newPath.getWideName());
337 m_styleSheetList.append(fpName);
338 }
339 } catch (...) {
340 }
341
342 // load rooms or layouts
343 TFilePath room_path(ToonzFolder::getRoomsDir());
344 TFilePathSet room_fpset;
345 try {
346 TSystem::readDirectory(room_fpset, room_path, true, false);
347 TFilePathSet::iterator it = room_fpset.begin();
348 for (int i = 0; it != room_fpset.end(); it++, i++) {
349 TFilePath newPath = *it;
350 if (newPath == room_path) continue;
351 if (TFileStatus(newPath).isDirectory()) {
352 QString string = QString::fromStdWString(newPath.getWideName());
353 m_roomMaps[i] = string;
354 }
355 }
356 } catch (...) {
357 }
358 }
359
360 //-----------------------------------------------------------------
361
definePreferenceItems()362 void Preferences::definePreferenceItems() {
363 // General
364 define(defaultViewerEnabled, "defaultViewerEnabled", QMetaType::Bool, false);
365 define(rasterOptimizedMemory, "rasterOptimizedMemory", QMetaType::Bool,
366 false);
367 define(startupPopupEnabled, "startupPopupEnabled", QMetaType::Bool, true);
368 define(undoMemorySize, "undoMemorySize", QMetaType::Int, 100, 0, 2000);
369 define(taskchunksize, "taskchunksize", QMetaType::Int, 10, 1, 2000);
370 define(sceneNumberingEnabled, "sceneNumberingEnabled", QMetaType::Bool,
371 false);
372 define(watchFileSystemEnabled, "watchFileSystemEnabled", QMetaType::Bool,
373 true);
374 define(projectRoot, "projectRoot", QMetaType::Int, 0x08);
375 define(customProjectRoot, "customProjectRoot", QMetaType::QString, "");
376 define(pathAliasPriority, "pathAliasPriority", QMetaType::Int,
377 (int)ProjectFolderOnly);
378
379 setCallBack(undoMemorySize, &Preferences::setUndoMemorySize);
380
381 // Interface
382 define(CurrentStyleSheetName, "CurrentStyleSheetName", QMetaType::QString,
383 "Default");
384
385 // Qt has a bug in recent versions that Menu item Does not show correctly
386 // (QTBUG-90242) Since the current OT is made to handle such issue, so we need
387 // to apply an extra adjustment when it is run on the older versions (5.9.x)
388 // of Qt
389 // Update: confirmed that the bug does not appear at least in Qt 5.12.8
390 QString defaultAditionalSheet = "";
391 #if QT_VERSION < QT_VERSION_CHECK(5, 12, 9)
392 defaultAditionalSheet = "QMenu::Item{ padding: 3 28 3 28; }";
393 #endif
394
395 define(additionalStyleSheet, "additionalStyleSheet", QMetaType::QString,
396 defaultAditionalSheet);
397 define(iconTheme, "iconTheme", QMetaType::Bool, false);
398 define(pixelsOnly, "pixelsOnly", QMetaType::Bool, false);
399 define(oldUnits, "oldUnits", QMetaType::QString, "mm");
400 define(oldCameraUnits, "oldCameraUnits", QMetaType::QString, "inch");
401 define(linearUnits, "linearUnits", QMetaType::QString, "mm");
402 define(cameraUnits, "cameraUnits", QMetaType::QString, "inch");
403 define(CurrentRoomChoice, "CurrentRoomChoice", QMetaType::QString, "Default");
404 define(functionEditorToggle, "functionEditorToggle", QMetaType::Int,
405 (int)ShowGraphEditorInPopup);
406 define(moveCurrentFrameByClickCellArea, "moveCurrentFrameByClickCellArea",
407 QMetaType::Bool, true);
408 define(actualPixelViewOnSceneEditingMode, "actualPixelViewOnSceneEditingMode",
409 QMetaType::Bool, false);
410 define(levelNameOnEachMarkerEnabled, "levelNameOnEachMarkerEnabled",
411 QMetaType::Bool, false);
412 define(showRasterImagesDarkenBlendedInViewer,
413 "showRasterImagesDarkenBlendedInViewer", QMetaType::Bool, false);
414 define(showFrameNumberWithLetters, "showFrameNumberWithLetters",
415 QMetaType::Bool, false);
416 define(iconSize, "iconSize", QMetaType::QSize, QSize(80, 45), QSize(10, 10),
417 QSize(400, 400));
418 define(viewShrink, "viewShrink", QMetaType::Int, 1, 1, 20);
419 define(viewStep, "viewStep", QMetaType::Int, 1, 1, 20);
420 define(viewerZoomCenter, "viewerZoomCenter", QMetaType::Int,
421 0); // Mouse Cursor
422 define(CurrentLanguageName, "CurrentLanguageName", QMetaType::QString,
423 "English");
424 #ifdef _WIN32
425 QString defaultFont("Segoe UI");
426 #elif defined Q_OS_MACOS
427 QString defaultFont("Helvetica Neue");
428 #else
429 QString defaultFont("Helvetica");
430 #endif
431 define(interfaceFont, "interfaceFont", QMetaType::QString, defaultFont);
432 define(interfaceFontStyle, "interfaceFontStyle", QMetaType::QString,
433 "Regular");
434 define(colorCalibrationEnabled, "colorCalibrationEnabled", QMetaType::Bool,
435 false);
436 define(colorCalibrationLutPaths, "colorCalibrationLutPaths",
437 QMetaType::QVariantMap, QVariantMap());
438
439 // hide menu icons by default in macOS since the icon color may not match with
440 // the system color theme
441 #ifdef Q_OS_MACOS
442 bool defIconsVisible = false;
443 #else
444 bool defIconsVisible = true;
445 #endif
446 define(showIconsInMenu, "showIconsInMenu", QMetaType::Bool, defIconsVisible);
447
448 setCallBack(pixelsOnly, &Preferences::setPixelsOnly);
449 setCallBack(linearUnits, &Preferences::setUnits);
450 setCallBack(cameraUnits, &Preferences::setCameraUnits);
451
452 // Visualization
453 define(show0ThickLines, "show0ThickLines", QMetaType::Bool, true);
454 define(regionAntialias, "regionAntialias", QMetaType::Bool, false);
455
456 // Loading
457 define(importPolicy, "importPolicy", QMetaType::Int, 0); // Always ask
458 define(autoExposeEnabled, "autoExposeEnabled", QMetaType::Bool, true);
459 define(subsceneFolderEnabled, "subsceneFolderEnabled", QMetaType::Bool, true);
460 define(removeSceneNumberFromLoadedLevelName,
461 "removeSceneNumberFromLoadedLevelName", QMetaType::Bool, false);
462 define(IgnoreImageDpi, "IgnoreImageDpi", QMetaType::Bool, false);
463 define(initialLoadTlvCachingBehavior, "initialLoadTlvCachingBehavior",
464 QMetaType::Int, 0); // On Demand
465 define(columnIconLoadingPolicy, "columnIconLoadingPolicy", QMetaType::Int,
466 (int)LoadAtOnce);
467 //"levelFormats" need to be handle separately
468
469 // Saving
470 define(autosaveEnabled, "autosaveEnabled", QMetaType::Bool, false);
471 define(autosavePeriod, "autosavePeriod", QMetaType::Int, 15, 1, 60);
472 define(autosaveSceneEnabled, "autosaveSceneEnabled", QMetaType::Bool, true);
473 define(autosaveOtherFilesEnabled, "autosaveOtherFilesEnabled",
474 QMetaType::Bool, true);
475 define(replaceAfterSaveLevelAs, "replaceAfterSaveLevelAs", QMetaType::Bool,
476 true);
477 define(backupEnabled, "backupEnabled", QMetaType::Bool, true);
478 define(backupKeepCount, "backupKeepCount", QMetaType::Int, 1, 1,
479 std::numeric_limits<int>::max());
480 define(rasterBackgroundColor, "rasterBackgroundColor", QMetaType::QColor,
481 QColor(Qt::white));
482 define(resetUndoOnSavingLevel, "resetUndoOnSavingLevel", QMetaType::Bool,
483 true);
484
485 setCallBack(rasterBackgroundColor, &Preferences::setRasterBackgroundColor);
486 setCallBack(autosaveEnabled, &Preferences::enableAutosave);
487 setCallBack(autosavePeriod, &Preferences::setAutosavePeriod);
488
489 // Import / Export
490 define(ffmpegPath, "ffmpegPath", QMetaType::QString, "");
491 define(ffmpegTimeout, "ffmpegTimeout", QMetaType::Int, 600, 1,
492 std::numeric_limits<int>::max());
493 define(fastRenderPath, "fastRenderPath", QMetaType::QString, "desktop");
494
495 // Drawing
496 define(scanLevelType, "scanLevelType", QMetaType::QString, "tif");
497 define(DefLevelType, "DefLevelType", QMetaType::Int, TZP_XSHLEVEL);
498 define(newLevelSizeToCameraSizeEnabled, "newLevelSizeToCameraSizeEnabled",
499 QMetaType::Bool, false);
500 define(DefLevelWidth, "DefLevelWidth", QMetaType::Double,
501 TCamera().getSize().lx, 0.1, std::numeric_limits<double>::max());
502 define(DefLevelHeight, "DefLevelHeight", QMetaType::Double,
503 TCamera().getSize().ly, 0.1, std::numeric_limits<double>::max());
504 define(DefLevelDpi, "DefLevelDpi", QMetaType::Double, TCamera().getDpi().x,
505 0.1, std::numeric_limits<double>::max());
506
507 define(EnableAutocreation, "EnableAutocreation", QMetaType::Bool, true);
508 define(NumberingSystem, "NumberingSystem", QMetaType::Int, 0); // Incremental
509 define(EnableAutoStretch, "EnableAutoStretch", QMetaType::Bool, true);
510 define(EnableCreationInHoldCells, "EnableCreationInHoldCells",
511 QMetaType::Bool, true);
512 define(EnableAutoRenumber, "EnableAutoRenumber", QMetaType::Bool, true);
513
514 define(vectorSnappingTarget, "vectorSnappingTarget", QMetaType::Int,
515 (int)SnapAll);
516 define(saveUnpaintedInCleanup, "saveUnpaintedInCleanup", QMetaType::Bool,
517 true);
518 define(minimizeSaveboxAfterEditing, "minimizeSaveboxAfterEditing",
519 QMetaType::Bool, true);
520 define(useNumpadForSwitchingStyles, "useNumpadForSwitchingStyles",
521 QMetaType::Bool, true);
522 define(downArrowInLevelStripCreatesNewFrame,
523 "downArrowInLevelStripCreatesNewFrame", QMetaType::Bool, true);
524 define(keepFillOnVectorSimplify, "keepFillOnVectorSimplify", QMetaType::Bool,
525 true);
526 define(useHigherDpiOnVectorSimplify, "useHigherDpiOnVectorSimplify",
527 QMetaType::Bool, false);
528
529 // Tools
530 define(dropdownShortcutsCycleOptions, "dropdownShortcutsCycleOptions",
531 QMetaType::Int,
532 1); // Cycle through the available options (changed from bool to int)
533 define(FillOnlysavebox, "FillOnlysavebox", QMetaType::Bool, false);
534 define(multiLayerStylePickerEnabled, "multiLayerStylePickerEnabled",
535 QMetaType::Bool, false);
536 define(cursorBrushType, "cursorBrushType", QMetaType::QString, "Small");
537 define(cursorBrushStyle, "cursorBrushStyle", QMetaType::QString, "Default");
538 define(cursorOutlineEnabled, "cursorOutlineEnabled", QMetaType::Bool, true);
539 define(levelBasedToolsDisplay, "levelBasedToolsDisplay", QMetaType::Int,
540 0); // Default
541 define(useCtrlAltToResizeBrush, "useCtrlAltToResizeBrush", QMetaType::Bool,
542 true);
543 define(tempToolSwitchTimer, "tempToolSwitchTimer", QMetaType::Int, 500, 1,
544 std::numeric_limits<int>::max());
545
546 // Xsheet
547 define(xsheetLayoutPreference, "xsheetLayoutPreference", QMetaType::QString,
548 "Classic-revised");
549 define(xsheetStep, "xsheetStep", QMetaType::Int, 10, 0,
550 std::numeric_limits<int>::max());
551 define(xsheetAutopanEnabled, "xsheetAutopanEnabled", QMetaType::Bool, true);
552 define(DragCellsBehaviour, "DragCellsBehaviour", QMetaType::Int,
553 1); // Cells and Column Data
554 define(ignoreAlphaonColumn1Enabled, "ignoreAlphaonColumn1Enabled",
555 QMetaType::Bool, false);
556 define(showKeyframesOnXsheetCellArea, "showKeyframesOnXsheetCellArea",
557 QMetaType::Bool, true);
558 define(showXsheetCameraColumn, "showXsheetCameraColumn", QMetaType::Bool,
559 true);
560 define(useArrowKeyToShiftCellSelection, "useArrowKeyToShiftCellSelection",
561 QMetaType::Bool, true);
562 define(inputCellsWithoutDoubleClickingEnabled,
563 "inputCellsWithoutDoubleClickingEnabled", QMetaType::Bool, false);
564 define(shortcutCommandsWhileRenamingCellEnabled,
565 "shortcutCommandsWhileRenamingCellEnabled", QMetaType::Bool, false);
566 define(showXSheetToolbar, "showXSheetToolbar", QMetaType::Bool, true);
567 define(expandFunctionHeader, "expandFunctionHeader", QMetaType::Bool, false);
568 define(showColumnNumbers, "showColumnNumbers", QMetaType::Bool, false);
569 define(syncLevelRenumberWithXsheet, "syncLevelRenumberWithXsheet",
570 QMetaType::Bool, true);
571 define(currentTimelineEnabled, "currentTimelineEnabled", QMetaType::Bool,
572 true);
573 define(currentColumnColor, "currentColumnColor", QMetaType::QColor,
574 QColor(Qt::yellow));
575
576 // Animation
577 define(keyframeType, "keyframeType", QMetaType::Int, 2); // Linear
578 define(animationStep, "animationStep", QMetaType::Int, 1, 1, 500);
579 define(modifyExpressionOnMovingReferences,
580 "modifyExpressionOnMovingReferences", QMetaType::Bool, false);
581
582 // Preview
583 define(blanksCount, "blanksCount", QMetaType::Int, 0, 0, 1000);
584 define(blankColor, "blankColor", QMetaType::QColor, QColor(Qt::white));
585 define(rewindAfterPlayback, "rewindAfterPlayback", QMetaType::Bool, true);
586 define(shortPlayFrameCount, "shortPlayFrameCount", QMetaType::Int, 8, 1, 100);
587 define(previewAlwaysOpenNewFlip, "previewAlwaysOpenNewFlip", QMetaType::Bool,
588 false);
589 define(fitToFlipbook, "fitToFlipbook", QMetaType::Bool, false);
590 define(generatedMovieViewEnabled, "generatedMovieViewEnabled",
591 QMetaType::Bool, true);
592
593 // Onion Skin
594 define(onionSkinEnabled, "onionSkinEnabled", QMetaType::Bool, true);
595 define(onionPaperThickness, "onionPaperThickness", QMetaType::Int, 50, 0,
596 100);
597 define(backOnionColor, "backOnionColor", QMetaType::QColor, QColor(Qt::red));
598 define(frontOnionColor, "frontOnionColor", QMetaType::QColor,
599 QColor(Qt::green));
600 define(onionInksOnly, "onionInksOnly", QMetaType::Bool, false);
601 define(onionSkinDuringPlayback, "onionSkinDuringPlayback", QMetaType::Bool,
602 false);
603 define(useOnionColorsForShiftAndTraceGhosts,
604 "useOnionColorsForShiftAndTraceGhosts", QMetaType::Bool, true);
605 define(animatedGuidedDrawing, "animatedGuidedDrawing", QMetaType::Int,
606 0); // Arrow Markers (changed from bool to int)
607
608 // Colors
609 define(viewerBGColor, "viewerBGColor", QMetaType::QColor,
610 QColor(128, 128, 128));
611 define(previewBGColor, "previewBGColor", QMetaType::QColor,
612 QColor(64, 64, 64));
613 define(levelEditorBoxColor, "levelEditorBoxColor", QMetaType::QColor,
614 QColor(128, 128, 128));
615 define(chessboardColor1, "chessboardColor1", QMetaType::QColor,
616 QColor(180, 180, 180));
617 define(chessboardColor2, "chessboardColor2", QMetaType::QColor,
618 QColor(230, 230, 230));
619 define(transpCheckInkOnWhite, "transpCheckInkOnWhite", QMetaType::QColor,
620 QColor(Qt::black));
621 define(transpCheckInkOnBlack, "transpCheckInkOnBlack", QMetaType::QColor,
622 QColor(Qt::white));
623 define(transpCheckPaint, "transpCheckPaint", QMetaType::QColor,
624 QColor(127, 127, 127));
625
626 // Version Control
627 define(SVNEnabled, "SVNEnabled", QMetaType::Bool, false);
628 define(automaticSVNFolderRefreshEnabled, "automaticSVNFolderRefreshEnabled",
629 QMetaType::Bool, true);
630 define(latestVersionCheckEnabled, "latestVersionCheckEnabled",
631 QMetaType::Bool, true);
632
633 // Touch / Tablet Settings
634 // TounchGestureControl // Touch Gesture is a checkable command and not in
635 // preferences.ini
636 define(winInkEnabled, "winInkEnabled", QMetaType::Bool, false);
637 // This option will be shown & available only when WITH_WINTAB is defined
638 define(useQtNativeWinInk, "useQtNativeWinInk", QMetaType::Bool, false);
639
640 // Others (not appeared in the popup)
641 // Shortcut popup settings
642 define(shortcutPreset, "shortcutPreset", QMetaType::QString, "defopentoonz");
643 // Viewer context menu
644 define(guidedDrawingType, "guidedDrawingType", QMetaType::Int, 0); // Off
645 define(guidedAutoInbetween, "guidedAutoInbetween", QMetaType::Bool,
646 false); // Off
647 define(guidedInterpolationType, "guidedInterpolationType", QMetaType::Int,
648 1); // Linear
649 #if defined(MACOSX) && defined(__LP64__)
650 // OSX shared memory settings
651 define(shmmax, "shmmax", QMetaType::Int, -1);
652 define(shmseg, "shmseg", QMetaType::Int, -1);
653 define(shmall, "shmall", QMetaType::Int, -1);
654 define(shmmni, "shmmni", QMetaType::Int, -1);
655 #endif
656 }
657
658 //-----------------------------------------------------------------
659
define(PreferencesItemId id,QString idString,QMetaType::Type type,QVariant defaultValue,QVariant min,QVariant max)660 void Preferences::define(PreferencesItemId id, QString idString,
661 QMetaType::Type type, QVariant defaultValue,
662 QVariant min, QVariant max) {
663 // load value
664 QVariant value(defaultValue);
665 switch (type) {
666 case QMetaType::Bool:
667 case QMetaType::Int:
668 case QMetaType::Double:
669 case QMetaType::QString:
670 if (m_settings->contains(idString) &&
671 m_settings->value(idString).canConvert(type))
672 value = m_settings->value(idString);
673 break;
674 case QMetaType::QSize: // used in iconSize
675 if (m_settings->contains(idString) &&
676 m_settings->value(idString).canConvert(QMetaType::QSize))
677 value = m_settings->value(idString);
678 // to keep compatibility with older versions
679 else if (m_settings->contains(idString + "X")) {
680 QSize size = value.toSize();
681 size.setWidth(m_settings->value(idString + "X", size.width()).toInt());
682 size.setHeight(m_settings->value(idString + "Y", size.height()).toInt());
683 value.setValue(size);
684 }
685 break;
686 case QMetaType::QMetaType::QColor:
687 if (m_settings->contains(idString)) {
688 QString str = m_settings->value(idString).toString();
689 value.setValue(stringToColor(str));
690 }
691 // following two conditions are to keep compatibility with older versions
692 else if (m_settings->contains(idString + "_R")) {
693 QColor color = value.value<QColor>();
694 color.setRed(m_settings->value(idString + "_R", color.red()).toInt());
695 color.setGreen(m_settings->value(idString + "_G", color.green()).toInt());
696 color.setBlue(m_settings->value(idString + "_B", color.blue()).toInt());
697 color.setAlpha(m_settings->value(idString + "_M", color.alpha()).toInt());
698 value.setValue(color);
699 } else if (m_settings->contains(idString + ".r")) {
700 QColor color = value.value<QColor>();
701 color.setRed(m_settings->value(idString + ".r", color.red()).toInt());
702 color.setGreen(m_settings->value(idString + ".g", color.green()).toInt());
703 color.setBlue(m_settings->value(idString + ".b", color.blue()).toInt());
704 color.setAlpha(255);
705 value.setValue(color);
706 }
707 break;
708 case QMetaType::QVariantMap: // used in colorCalibrationLutPaths
709 if (m_settings->contains(idString) &&
710 m_settings->value(idString).canConvert(type)) {
711 QMap<QString, QString> pathMap;
712 QAssociativeIterable iterable =
713 m_settings->value(idString).value<QAssociativeIterable>();
714 QAssociativeIterable::const_iterator it = iterable.begin();
715 const QAssociativeIterable::const_iterator end = iterable.end();
716 for (; it != end; ++it)
717 pathMap.insert(it.key().toString(), it.value().toString());
718 value.setValue(pathMap);
719 }
720 break;
721 default:
722 std::cout << "Unsupported type detected" << std::endl;
723 // load anyway
724 value = m_settings->value(idString, value);
725 break;
726 }
727
728 m_items.insert(id, PreferencesItem(idString, type, value, min, max));
729 }
730
731 //-----------------------------------------------------------------
732
setCallBack(const PreferencesItemId id,OnEditedFunc func)733 void Preferences::setCallBack(const PreferencesItemId id, OnEditedFunc func) {
734 getItem(id).onEditedFunc = func;
735 }
736
737 //-----------------------------------------------------------------
738
resolveCompatibility()739 void Preferences::resolveCompatibility() {
740 // autocreation type is divided into "EnableAutocreation" and
741 // "NumberingSystem"
742 if (m_settings->contains("AutocreationType") &&
743 !m_settings->contains("EnableAutocreation")) {
744 int type = m_settings->value("AutocreationType").toInt();
745 switch (type) {
746 case 0: // former "Disabled"
747 setValue(EnableAutocreation, false);
748 break;
749 case 1: // former "Enabled"
750 setValue(EnableAutocreation, true);
751 setValue(NumberingSystem, 0); // set numbering system to "Incremental"
752 break;
753 case 2: // former "Use Xsheet as Animation Sheet"
754 setValue(EnableAutocreation, true);
755 setValue(NumberingSystem, 1);
756 break;
757 }
758 }
759 }
760
761 //-----------------------------------------------------------------
762
getItem(const PreferencesItemId id)763 PreferencesItem &Preferences::getItem(const PreferencesItemId id) {
764 assert(m_items.contains(id));
765 return m_items[id];
766 }
767
768 //-----------------------------------------------------------------
769
getBoolValue(const PreferencesItemId id) const770 bool Preferences::getBoolValue(const PreferencesItemId id) const {
771 assert(m_items.contains(id));
772 if (!m_items.contains(id)) return false;
773 PreferencesItem item = m_items.value(id);
774 assert(item.type == QMetaType::Bool);
775 if (item.type != QMetaType::Bool) return false;
776
777 return item.value.toBool();
778 }
779
780 //-----------------------------------------------------------------
781
getIntValue(const PreferencesItemId id) const782 int Preferences::getIntValue(const PreferencesItemId id) const {
783 assert(m_items.contains(id));
784 if (!m_items.contains(id)) return -1;
785 PreferencesItem item = m_items.value(id);
786 assert(item.type == QMetaType::Int);
787 if (item.type != QMetaType::Int) return -1;
788
789 return item.value.toInt();
790 }
791
792 //-----------------------------------------------------------------
793
getDoubleValue(const PreferencesItemId id) const794 double Preferences::getDoubleValue(const PreferencesItemId id) const {
795 assert(m_items.contains(id));
796 if (!m_items.contains(id)) return -1.0;
797 PreferencesItem item = m_items.value(id);
798 assert(item.type == QMetaType::Double);
799 if (item.type != QMetaType::Double) return -1.0;
800
801 return item.value.toDouble();
802 }
803
804 //-----------------------------------------------------------------
805
getStringValue(const PreferencesItemId id) const806 QString Preferences::getStringValue(const PreferencesItemId id) const {
807 assert(m_items.contains(id));
808 if (!m_items.contains(id)) return QString();
809 PreferencesItem item = m_items.value(id);
810 assert(item.type == QMetaType::QString);
811 if (item.type != QMetaType::QString) return QString();
812
813 return item.value.toString();
814 }
815
816 //-----------------------------------------------------------------
817
getColorValue(const PreferencesItemId id) const818 TPixel Preferences::getColorValue(const PreferencesItemId id) const {
819 assert(m_items.contains(id));
820 if (!m_items.contains(id)) return TPixel();
821 PreferencesItem item = m_items.value(id);
822 assert(item.type == QMetaType::QColor);
823 if (item.type != QMetaType::QColor) return TPixel();
824
825 return colorToTPixel(item.value.value<QColor>());
826 }
827
828 //-----------------------------------------------------------------
829
getSizeValue(const PreferencesItemId id) const830 TDimension Preferences::getSizeValue(const PreferencesItemId id) const {
831 assert(m_items.contains(id));
832 if (!m_items.contains(id)) return TDimension();
833 PreferencesItem item = m_items.value(id);
834 assert(item.type == QMetaType::QSize);
835 if (item.type != QMetaType::QSize) return TDimension();
836 QSize size = item.value.toSize();
837 return TDimension(size.width(), size.height());
838 }
839
840 //-----------------------------------------------------------------
841 // saveToFile is true by default, becomes false when dragging color field
setValue(const PreferencesItemId id,QVariant value,bool saveToFile)842 void Preferences::setValue(const PreferencesItemId id, QVariant value,
843 bool saveToFile) {
844 assert(m_items.contains(id));
845 if (!m_items.contains(id)) return;
846 m_items[id].value = value;
847 if (saveToFile) {
848 if (m_items[id].type ==
849 QMetaType::QColor) // write in human-readable format
850 m_settings->setValue(m_items[id].idString,
851 colorToString(value.value<QColor>()));
852 else if (m_items[id].type ==
853 QMetaType::Bool) // write 1/0 instead of true/false to keep
854 // compatibility
855 m_settings->setValue(m_items[id].idString, value.toBool() ? "1" : "0");
856 else
857 m_settings->setValue(m_items[id].idString, value);
858 }
859
860 // execute callback
861 if (m_items[id].onEditedFunc) (this->*(m_items[id].onEditedFunc))();
862 }
863
864 //-----------------------------------------------------------------
865
enableAutosave()866 void Preferences::enableAutosave() {
867 bool autoSaveOn = getBoolValue(autosaveEnabled);
868 if (autoSaveOn)
869 emit startAutoSave();
870 else
871 emit stopAutoSave();
872 }
873
874 //-----------------------------------------------------------------
875
setAutosavePeriod()876 void Preferences::setAutosavePeriod() {
877 emit stopAutoSave();
878 emit startAutoSave();
879 emit autoSavePeriodChanged();
880 }
881
882 //-----------------------------------------------------------------
883
setUndoMemorySize()884 void Preferences::setUndoMemorySize() {
885 int memorySize = getIntValue(undoMemorySize);
886 TUndoManager::manager()->setUndoMemorySize(memorySize);
887 }
888
889 //-----------------------------------------------------------------
890
setPixelsOnly()891 void Preferences::setPixelsOnly() {
892 bool pixelSelected = getBoolValue(pixelsOnly);
893 if (pixelSelected)
894 storeOldUnits();
895 else
896 resetOldUnits();
897 }
898
899 //-----------------------------------------------------------------
900
setUnits()901 void Preferences::setUnits() {
902 std::string units = getStringValue(linearUnits).toStdString();
903 setCurrentUnits("length", units);
904 setCurrentUnits("length.x", units);
905 setCurrentUnits("length.y", units);
906 setCurrentUnits("length.lx", units);
907 setCurrentUnits("length.ly", units);
908 setCurrentUnits("fxLength", units);
909 setCurrentUnits("pippo", units);
910 }
911
912 //-----------------------------------------------------------------
913
setCameraUnits()914 void Preferences::setCameraUnits() {
915 std::string units = getStringValue(cameraUnits).toStdString();
916 setCurrentUnits("camera.lx", units);
917 setCurrentUnits("camera.ly", units);
918 }
919
920 //-----------------------------------------------------------------
921
setRasterBackgroundColor()922 void Preferences::setRasterBackgroundColor() {
923 TPixel color = getColorValue(rasterBackgroundColor);
924 TImageWriter::setBackgroundColor(color);
925 }
926
927 //-----------------------------------------------------------------
928
storeOldUnits()929 void Preferences::storeOldUnits() {
930 setValue(oldUnits, getStringValue(linearUnits));
931 setValue(oldCameraUnits, getStringValue(cameraUnits));
932 }
933
934 //-----------------------------------------------------------------
935
resetOldUnits()936 void Preferences::resetOldUnits() {
937 QString oldLinearU = getStringValue(oldUnits);
938 QString oldCameraU = getStringValue(oldCameraUnits);
939 if (oldLinearU != "" && oldCameraU != "") {
940 setValue(linearUnits, oldLinearU);
941 setValue(cameraUnits, oldCameraU);
942 }
943 }
944
945 //-----------------------------------------------------------------
946
getCurrentLanguage() const947 QString Preferences::getCurrentLanguage() const {
948 QString lang = getStringValue(CurrentLanguageName);
949 if (m_languageList.contains(lang)) return lang;
950 // If no valid option selected, then return English
951 return m_languageList[0];
952 }
953
954 //-----------------------------------------------------------------
955
getCurrentStyleSheet() const956 QString Preferences::getCurrentStyleSheet() const {
957 QString currentStyleSheetName = getStringValue(CurrentStyleSheetName);
958 if (currentStyleSheetName.isEmpty()) return QString();
959 TFilePath path(TEnv::getConfigDir() + "qss");
960 QString string = currentStyleSheetName + QString("/") +
961 currentStyleSheetName + QString(".qss");
962 QString styleSheetPath = path.getQString() + "/" + string;
963
964 QString additionalSheetStr = getStringValue(additionalStyleSheet);
965 // if there is no additional style sheet, return the path and let
966 // Qt to load and parse it
967 if (additionalSheetStr.isEmpty()) return QString("file:///" + styleSheetPath);
968
969 // if there is any additional style sheet, load the style sheet
970 // from the file and combine with it
971 QString styleSheetStr;
972 QFile f(styleSheetPath);
973 if (f.open(QFile::ReadOnly | QFile::Text)) {
974 QTextStream ts(&f);
975 styleSheetStr = ts.readAll();
976 }
977 styleSheetStr += additionalSheetStr;
978
979 // here we will convert all relative paths to absolute paths
980 // or Qt will look for images relative to the current working directory
981 // since it has no idea where the style sheet comes from.
982
983 QString currentStyleFolderPath =
984 path.getQString().replace("\\", "/") + "/" + currentStyleSheetName;
985
986 styleSheetStr.replace(QRegExp("url\\(['\"]([^'\"]+)['\"]\\)"),
987 "url(\"" + currentStyleFolderPath + QString("/\\1\")"));
988
989 return styleSheetStr;
990 }
991
992 //-----------------------------------------------------------------
993
setPrecompute(bool enabled)994 void Preferences::setPrecompute(bool enabled) { m_precompute = enabled; }
995
996 //-----------------------------------------------------------------
997
addLevelFormat(const LevelFormat & format)998 int Preferences::addLevelFormat(const LevelFormat &format) {
999 LevelFormatVector::iterator lft = m_levelFormats.insert(
1000 std::upper_bound(m_levelFormats.begin(), m_levelFormats.end(), format,
1001 formatLess),
1002 format);
1003
1004 int formatIdx = int(
1005 lft -
1006 m_levelFormats.begin()); // NOTE: Must be disjoint from the instruction
1007 // above, since operator-'s param evaluation
1008 // order is unspecified
1009 _setValue(*m_settings, m_levelFormats);
1010
1011 return formatIdx;
1012 }
1013
1014 //-----------------------------------------------------------------
1015
removeLevelFormat(int formatIdx)1016 void Preferences::removeLevelFormat(int formatIdx) {
1017 assert(0 <= formatIdx && formatIdx < int(m_levelFormats.size()));
1018 m_levelFormats.erase(m_levelFormats.begin() + formatIdx);
1019
1020 _setValue(*m_settings, m_levelFormats);
1021 }
1022
1023 //-----------------------------------------------------------------
1024
levelFormat(int formatIdx) const1025 const Preferences::LevelFormat &Preferences::levelFormat(int formatIdx) const {
1026 assert(0 <= formatIdx && formatIdx < int(m_levelFormats.size()));
1027 return m_levelFormats[formatIdx];
1028 }
1029
1030 //-----------------------------------------------------------------
1031
levelFormatsCount() const1032 int Preferences::levelFormatsCount() const {
1033 return int(m_levelFormats.size());
1034 }
1035
1036 //-----------------------------------------------------------------
1037
matchLevelFormat(const TFilePath & fp) const1038 int Preferences::matchLevelFormat(const TFilePath &fp) const {
1039 LevelFormatVector::const_iterator lft =
1040 std::find_if(m_levelFormats.begin(), m_levelFormats.end(),
1041 boost::bind(&LevelFormat::matches, _1, boost::cref(fp)));
1042
1043 return (lft != m_levelFormats.end()) ? lft - m_levelFormats.begin() : -1;
1044 }
1045
1046 //-----------------------------------------------------------------
1047
setColorCalibrationLutPath(QString monitorName,QString path)1048 void Preferences::setColorCalibrationLutPath(QString monitorName,
1049 QString path) {
1050 PreferencesItem item = m_items.value(colorCalibrationLutPaths);
1051 QMap<QString, QVariant> lutPathMap =
1052 item.value.value<QMap<QString, QVariant>>();
1053 lutPathMap.insert(monitorName, path);
1054 setValue(colorCalibrationLutPaths, lutPathMap);
1055 }
1056
1057 //-----------------------------------------------------------------
1058
getColorCalibrationLutPath(QString & monitorName) const1059 QString Preferences::getColorCalibrationLutPath(QString &monitorName) const {
1060 PreferencesItem item = m_items.value(colorCalibrationLutPaths);
1061 QMap<QString, QVariant> lutPathMap =
1062 item.value.value<QMap<QString, QVariant>>();
1063
1064 return lutPathMap.value(monitorName).toString();
1065 }
1066