diff --git a/data/strings/en.ini b/data/strings/en.ini
index 4e7049cdc..5889f5b74 100644
--- a/data/strings/en.ini
+++ b/data/strings/en.ini
@@ -111,6 +111,7 @@ overwrite_existent_file = Warning<
+
+
@@ -605,6 +607,19 @@
pref="tileset.cache_compressed_tilesets" />
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/commands/cmd_options.cpp b/src/app/commands/cmd_options.cpp
index 4814ae5dd..47ca61640 100644
--- a/src/app/commands/cmd_options.cpp
+++ b/src/app/commands/cmd_options.cpp
@@ -25,6 +25,7 @@
#include "app/pref/preferences.h"
#include "app/recent_files.h"
#include "app/resource_finder.h"
+#include "app/tools/tool_box.h"
#include "app/tx.h"
#include "app/ui/best_fit_criteria_selector.h"
#include "app/ui/color_button.h"
@@ -272,14 +273,7 @@ public:
// Theme variants
fillThemeVariants();
- // Default extension to save files
- fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
- fillExtensionsCombobox(exportImageDefaultExtension(), m_pref.exportFile.imageDefaultExtension());
- fillExtensionsCombobox(exportAnimationDefaultExtension(), m_pref.exportFile.animationDefaultExtension());
- fillExtensionsCombobox(exportSpriteSheetDefaultExtension(), m_pref.spriteSheet.defaultExtension());
-
- // Number of recent items
- recentFiles()->setValue(m_pref.general.recentItems());
+ // Recent files
clearRecentFiles()->Click.connect([this]{ onClearRecentFiles(); });
// Template item for active display color profiles
@@ -295,31 +289,24 @@ public:
if (cs->gfxColorSpace()->type() != gfx::ColorSpace::None)
workingRgbCs()->addItem(new ColorSpaceItem(cs));
}
- updateColorProfileControls(m_pref.color.manage(),
- m_pref.color.windowProfile(),
- m_pref.color.windowProfileName(),
- m_pref.color.workingRgbSpace(),
- m_pref.color.filesWithProfile(),
- m_pref.color.missingProfile());
}
// Alerts
- openSequence()->setSelectedItemIndex(int(m_pref.openFile.openSequence()));
resetAlerts()->Click.connect([this]{ onResetAlerts(); });
// Cursor
- paintingCursorType()->setSelectedItemIndex(int(m_pref.cursor.paintingCursorType()));
- cursorColor()->setColor(m_pref.cursor.cursorColor());
-
- if (cursorColor()->getColor().getType() == app::Color::MaskType) {
- cursorColorType()->setSelectedItemIndex(0);
- cursorColor()->setVisible(false);
- }
- else {
- cursorColorType()->setSelectedItemIndex(1);
- cursorColor()->setVisible(true);
- }
cursorColorType()->Change.connect([this]{ onCursorColorType(); });
+ nativeCursor()->Click.connect([this]{ onNativeCursorChange(); });
+
+ // Dialogs
+ showAsepriteFileDialog()->Click.connect([this]{
+ nativeFileDialog()->setSelected(
+ !showAsepriteFileDialog()->isSelected());
+ });
+ nativeFileDialog()->Click.connect([this]{
+ showAsepriteFileDialog()->setSelected(
+ !nativeFileDialog()->isSelected());
+ });
// Grid
gridW()->Leave.connect([this] {
@@ -333,27 +320,10 @@ public:
gridH()->setText("1");
});
- // Brush preview
- brushPreview()->setSelectedItemIndex(
- (int)m_pref.cursor.brushPreview());
-
- // Guide colors
- layerEdgesColor()->setColor(m_pref.guides.layerEdgesColor());
- autoGuidesColor()->setColor(m_pref.guides.autoGuidesColor());
-
- // Slices default color
- defaultSliceColor()->setColor(m_pref.slices.defaultColor());
-
// Timeline
- firstFrame()->setTextf("%d", m_globPref.timeline.firstFrame());
resetTimelineSel()->Click.connect([this]{ onResetTimelineSel(); });
// Others
- if (m_pref.general.expandMenubarOnMouseover())
- expandMenubarOnMouseover()->setSelected(true);
-
- if (m_pref.general.dataRecovery())
- enableDataRecovery()->setSelected(true);
enableDataRecovery()->Click.connect(
[this](){
const bool state = enableDataRecovery()->isSelected();
@@ -362,101 +332,10 @@ public:
keepEditedSpriteDataFor()->setEnabled(state);
});
- if (m_pref.general.dataRecovery() &&
- m_pref.general.keepEditedSpriteData())
- keepEditedSpriteData()->setSelected(true);
- else if (!m_pref.general.dataRecovery()) {
- keepEditedSpriteData()->setEnabled(false);
- keepEditedSpriteDataFor()->setEnabled(false);
- }
-
- if (m_pref.general.keepClosedSpriteOnMemory())
- keepClosedSpriteOnMemory()->setSelected(true);
-
- if (m_pref.general.showFullPath())
- showFullPath()->setSelected(true);
-
- dataRecoveryPeriod()->setSelectedItemIndex(
- dataRecoveryPeriod()->findItemIndexByValue(
- base::convert_to(m_pref.general.dataRecoveryPeriod())));
-
- keepEditedSpriteDataFor()->setSelectedItemIndex(
- keepEditedSpriteDataFor()->findItemIndexByValue(
- base::convert_to(m_pref.general.keepEditedSpriteDataFor())));
-
- keepClosedSpriteOnMemoryFor()->setSelectedItemIndex(
- keepClosedSpriteOnMemoryFor()->findItemIndexByValue(
- base::convert_to(m_pref.general.keepClosedSpriteOnMemoryFor())));
-
- if (m_pref.editor.zoomFromCenterWithWheel())
- zoomFromCenterWithWheel()->setSelected(true);
-
- if (m_pref.editor.zoomFromCenterWithKeys())
- zoomFromCenterWithKeys()->setSelected(true);
-
- if (m_pref.selection.autoOpaque())
- autoOpaque()->setSelected(true);
-
- if (m_pref.selection.keepSelectionAfterClear())
- keepSelectionAfterClear()->setSelected(true);
-
- if (m_pref.selection.autoShowSelectionEdges())
- autoShowSelectionEdges()->setSelected(true);
-
- if (m_pref.selection.moveEdges())
- moveEdges()->setSelected(true);
-
- if (m_pref.selection.modifiersDisableHandles())
- modifiersDisableHandles()->setSelected(true);
-
- if (m_pref.selection.moveOnAddMode())
- moveOnAddMode()->setSelected(true);
-
- // If the platform supports native cursors...
- if ((int(os::instance()->capabilities()) &
- int(os::Capabilities::CustomMouseCursor)) != 0) {
- if (m_pref.cursor.useNativeCursor())
- nativeCursor()->setSelected(true);
- nativeCursor()->Click.connect([this]{ onNativeCursorChange(); });
-
- cursorScale()->setSelectedItemIndex(
- cursorScale()->findItemIndexByValue(
- base::convert_to(m_pref.cursor.cursorScale())));
- }
- else {
- nativeCursor()->setEnabled(false);
- }
-
- onNativeCursorChange();
-
- // "Show Aseprite file dialog" option is the inverse of the old
- // experimental "use native file dialog" option
- showAsepriteFileDialog()->setSelected(
- !m_pref.experimental.useNativeFileDialog());
- showAsepriteFileDialog()->Click.connect([this]{
- nativeFileDialog()->setSelected(
- !showAsepriteFileDialog()->isSelected());
- });
- nativeFileDialog()->Click.connect([this]{
- showAsepriteFileDialog()->setSelected(
- !nativeFileDialog()->isSelected());
- });
-
#ifdef LAF_WINDOWS // Show Tablet section on Windows
- {
- const os::TabletAPI tabletAPI = os::instance()->tabletOptions().api;
- if (tabletAPI == os::TabletAPI::Wintab)
- tabletApiWintabSystem()->setSelected(true);
- else if (tabletAPI == os::TabletAPI::WintabPackets)
- tabletApiWintabDirect()->setSelected(true);
- else
- tabletApiWindowsPointer()->setSelected(true);
- onTabletAPIChange();
-
- tabletApiWindowsPointer()->Click.connect([this](){ onTabletAPIChange(); });
- tabletApiWintabSystem()->Click.connect([this](){ onTabletAPIChange(); });
- tabletApiWintabDirect()->Click.connect([this](){ onTabletAPIChange(); });
- }
+ tabletApiWindowsPointer()->Click.connect([this](){ onTabletAPIChange(); });
+ tabletApiWintabSystem()->Click.connect([this](){ onTabletAPIChange(); });
+ tabletApiWintabDirect()->Click.connect([this](){ onTabletAPIChange(); });
#else // For macOS and Linux
{
// Hide the "section_tablet" item (which is only for Windows at the moment)
@@ -470,30 +349,11 @@ public:
}
#endif
- if (m_pref.experimental.flashLayer())
- flashLayer()->setSelected(true);
-
- nonactiveLayersOpacity()->setValue(m_pref.experimental.nonactiveLayersOpacity());
-
rgbmapAlgorithmPlaceholder()->addChild(&m_rgbmapAlgorithmSelector);
m_rgbmapAlgorithmSelector.setExpansive(true);
- m_rgbmapAlgorithmSelector.algorithm(m_pref.quantization.rgbmapAlgorithm());
bestFitCriteriaPlaceholder()->addChild(&m_bestFitCriteriaSelector);
m_bestFitCriteriaSelector.setExpansive(true);
- m_bestFitCriteriaSelector.criteria(m_pref.quantization.fitCriteria());
-
- if (m_pref.editor.showScrollbars())
- showScrollbars()->setSelected(true);
-
- if (m_pref.editor.autoScroll())
- autoScroll()->setSelected(true);
-
- if (m_pref.editor.straightLinePreview())
- straightLinePreview()->setSelected(true);
-
- if (m_pref.eyedropper.discardBrush())
- discardBrush()->setSelected(true);
// Scope
bgScope()->addItem(Strings::options_bg_for_new_docs());
@@ -508,9 +368,6 @@ public:
gridScope()->Change.connect([this]{ onChangeGridScope(); });
}
- // Update the one/multiple window buttonset (and keep in on sync
- // with the old/experimental checkbox)
- uiWindows()->setSelectedItem(multipleWindows()->isSelected() ? 1: 0);
uiWindows()->ItemChange.connect([this]() {
multipleWindows()->setSelected(uiWindows()->selectedItem() == 1);
});
@@ -518,29 +375,17 @@ public:
uiWindows()->setSelectedItem(multipleWindows()->isSelected() ? 1: 0);
});
- // Scaling
- selectScalingItems();
-
-#ifdef ENABLE_DEVMODE // TODO enable this on Release when Aseprite supports
- // GPU-acceleration properly
- if (os::instance()->hasCapability(os::Capabilities::GpuAccelerationSwitch)) {
- gpuAcceleration()->setSelected(m_pref.general.gpuAcceleration());
- }
- else
-#endif
- {
+#ifndef ENABLE_DEVMODE // TODO enable this on Release when Aseprite supports
+ // GPU-acceleration properly
+ if (!os::instance()->hasCapability(os::Capabilities::GpuAccelerationSwitch))
gpuAcceleration()->setVisible(false);
- }
+#endif
// If the platform does support native menus, we show the option,
// in other case, the option doesn't make sense for this platform.
- if (os::instance()->menus())
- showMenuBar()->setSelected(m_pref.general.showMenuBar());
- else
+ if (!os::instance()->menus())
showMenuBar()->setVisible(false);
- showHome()->setSelected(m_pref.general.showHome());
-
// Editor sampling
samplingPlaceholder()->addChild(
m_samplingSelector = new SamplingSelector(
@@ -568,7 +413,6 @@ public:
rightClickBehavior()->addItem(Strings::options_right_click_rectangular_marquee());
rightClickBehavior()->addItem(Strings::options_right_click_lasso());
rightClickBehavior()->addItem(Strings::options_right_click_select_layer_and_move());
- rightClickBehavior()->setSelectedItemIndex((int)m_pref.editor.rightClickMode());
#ifndef __APPLE__ // Zoom sliding two fingers option only on macOS
slideZoom()->setVisible(false);
@@ -606,11 +450,6 @@ public:
// Undo preferences
limitUndo()->Click.connect([this]{ onLimitUndoCheck(); });
- limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0);
- onLimitUndoCheck();
-
- undoGotoModified()->setSelected(m_pref.undo.gotoModified());
- undoAllowNonlinearHistory()->setSelected(m_pref.undo.allowNonlinearHistory());
// Theme buttons
themeList()->Change.connect([this]{ onThemeChange(); });
@@ -625,13 +464,27 @@ public:
uninstallExtension()->Click.connect([this]{ onUninstallExtension(); });
openExtensionFolder()->Click.connect([this]{ onOpenExtensionFolder(); });
+ // Reset checkboxes
+
+ // Prevent the user from clicking "Reset" if they don't have anything selected.
+ auto validateYesButton = [this] {
+ resetSelectedButton()->setEnabled(
+ defaultReset()->isSelected() || installedReset()->isSelected() ||
+ recentReset()->isSelected() || perfileReset()->isSelected() ||
+ toolsReset()->isSelected());
+ };
+ defaultReset()->Click.connect(validateYesButton);
+ installedReset()->Click.connect(validateYesButton);
+ recentReset()->Click.connect(validateYesButton);
+ perfileReset()->Click.connect(validateYesButton);
+ toolsReset()->Click.connect(validateYesButton);
+ resetSelectedButton()->Click.connect([this] { onResetDefault(); });
+
+ defaultReset()->setSelected(true);
+
// Apply button
buttonApply()->Click.connect([this]{ onApply(); });
- onChangeBgScope();
- onChangeGridScope();
- sectionListbox()->selectIndex(m_curSection);
-
// Refill languages combobox when extensions are enabled/disabled
m_extLanguagesChanges =
App::instance()->extensions().LanguagesChange.connect(
@@ -641,15 +494,178 @@ public:
m_extThemesChanges =
App::instance()->extensions().ThemesChange.connect(
[this]{ reloadThemes(); });
+
+ loadFromPreferences();
+ }
+
+ void loadFromPreferences() {
+ // Default extension to save files
+ fillExtensionsCombobox(defaultExtension(), m_pref.saveFile.defaultExtension());
+ fillExtensionsCombobox(exportImageDefaultExtension(), m_pref.exportFile.imageDefaultExtension());
+ fillExtensionsCombobox(exportAnimationDefaultExtension(), m_pref.exportFile.animationDefaultExtension());
+ fillExtensionsCombobox(exportSpriteSheetDefaultExtension(), m_pref.spriteSheet.defaultExtension());
+
+ // Number of recent items
+ recentFiles()->setValue(m_pref.general.recentItems());
+
+ // Color profiles
+ updateColorProfileControls(m_pref.color.manage(),
+ m_pref.color.windowProfile(),
+ m_pref.color.windowProfileName(),
+ m_pref.color.workingRgbSpace(),
+ m_pref.color.filesWithProfile(),
+ m_pref.color.missingProfile());
+
+ // Alerts
+ openSequence()->setSelectedItemIndex(int(m_pref.openFile.openSequence()));
+
+ // Cursor
+ paintingCursorType()->setSelectedItemIndex(int(m_pref.cursor.paintingCursorType()));
+ cursorColor()->setColor(m_pref.cursor.cursorColor());
+
+ if (cursorColor()->getColor().getType() == app::Color::MaskType) {
+ cursorColorType()->setSelectedItemIndex(0);
+ cursorColor()->setVisible(false);
+ }
+ else {
+ cursorColorType()->setSelectedItemIndex(1);
+ cursorColor()->setVisible(true);
+ }
+
+ // Brush preview
+ brushPreview()->setSelectedItemIndex(
+ (int)m_pref.cursor.brushPreview());
+
+ // Guide colors
+ layerEdgesColor()->setColor(m_pref.guides.layerEdgesColor());
+ autoGuidesColor()->setColor(m_pref.guides.autoGuidesColor());
+
+ // Slices default color
+ defaultSliceColor()->setColor(m_pref.slices.defaultColor());
+
+ // Timeline
+ firstFrame()->setTextf("%d", m_globPref.timeline.firstFrame());
+
+ // Others
+ expandMenubarOnMouseover()->setSelected(m_pref.general.expandMenubarOnMouseover());
+
+ enableDataRecovery()->setSelected(m_pref.general.dataRecovery());
+
+ if (m_pref.general.dataRecovery() &&
+ m_pref.general.keepEditedSpriteData())
+ keepEditedSpriteData()->setSelected(true);
+ else if (!m_pref.general.dataRecovery()) {
+ keepEditedSpriteData()->setEnabled(false);
+ keepEditedSpriteDataFor()->setEnabled(false);
+ }
+
+ keepClosedSpriteOnMemory()->setSelected(m_pref.general.keepClosedSpriteOnMemory());
+ showFullPath()->setSelected(m_pref.general.showFullPath());
+
+ dataRecoveryPeriod()->setSelectedItemIndex(
+ dataRecoveryPeriod()->findItemIndexByValue(
+ base::convert_to(m_pref.general.dataRecoveryPeriod())));
+
+ keepEditedSpriteDataFor()->setSelectedItemIndex(
+ keepEditedSpriteDataFor()->findItemIndexByValue(
+ base::convert_to(m_pref.general.keepEditedSpriteDataFor())));
+
+ keepClosedSpriteOnMemoryFor()->setSelectedItemIndex(
+ keepClosedSpriteOnMemoryFor()->findItemIndexByValue(
+ base::convert_to(m_pref.general.keepClosedSpriteOnMemoryFor())));
+
+ zoomFromCenterWithWheel()->setSelected(m_pref.editor.zoomFromCenterWithWheel());
+ zoomFromCenterWithKeys()->setSelected(m_pref.editor.zoomFromCenterWithKeys());
+ autoOpaque()->setSelected(m_pref.selection.autoOpaque());
+ keepSelectionAfterClear()->setSelected(m_pref.selection.keepSelectionAfterClear());
+ autoShowSelectionEdges()->setSelected( m_pref.selection.autoShowSelectionEdges());
+ moveEdges()->setSelected(m_pref.selection.moveEdges());
+ modifiersDisableHandles()->setSelected(m_pref.selection.modifiersDisableHandles());
+ moveOnAddMode()->setSelected(m_pref.selection.moveOnAddMode());
+
+ // If the platform supports native cursors...
+ if ((int(os::instance()->capabilities()) &
+ int(os::Capabilities::CustomMouseCursor)) != 0) {
+ nativeCursor()->setSelected(m_pref.cursor.useNativeCursor());
+
+ cursorScale()->setSelectedItemIndex(
+ cursorScale()->findItemIndexByValue(
+ base::convert_to(m_pref.cursor.cursorScale())));
+ }
+ else {
+ nativeCursor()->setEnabled(false);
+ }
+
+ onNativeCursorChange();
+
+ // "Show Aseprite file dialog" option is the inverse of the old
+ // experimental "use native file dialog" option
+ showAsepriteFileDialog()->setSelected(
+ !m_pref.experimental.useNativeFileDialog());
+
+#ifdef LAF_WINDOWS // Show Tablet section on Windows
+ {
+ const os::TabletAPI tabletAPI = os::instance()->tabletOptions().api;
+ if (tabletAPI == os::TabletAPI::Wintab)
+ tabletApiWintabSystem()->setSelected(true);
+ else if (tabletAPI == os::TabletAPI::WintabPackets)
+ tabletApiWintabDirect()->setSelected(true);
+ else
+ tabletApiWindowsPointer()->setSelected(true);
+
+ onTabletAPIChange();
+ }
+#endif
+
+ flashLayer()->setSelected(m_pref.experimental.flashLayer());
+ nonactiveLayersOpacity()->setValue(m_pref.experimental.nonactiveLayersOpacity());
+
+ m_rgbmapAlgorithmSelector.algorithm(m_pref.quantization.rgbmapAlgorithm());
+ m_bestFitCriteriaSelector.criteria(m_pref.quantization.fitCriteria());
+
+ showScrollbars()->setSelected(m_pref.editor.showScrollbars());
+ autoScroll()->setSelected(m_pref.editor.autoScroll());
+ straightLinePreview()->setSelected(m_pref.editor.straightLinePreview());
+ discardBrush()->setSelected(m_pref.eyedropper.discardBrush());
+
+ // Update the one/multiple window buttonset (and keep in on sync
+ // with the old/experimental checkbox)
+ uiWindows()->setSelectedItem(multipleWindows()->isSelected() ? 1 : 0);
+
+ // Scaling
+ selectScalingItems();
+
+ if (os::instance()->hasCapability(os::Capabilities::GpuAccelerationSwitch)) {
+ gpuAcceleration()->setSelected(m_pref.general.gpuAcceleration());
+ }
+
+ if (os::instance()->menus())
+ showMenuBar()->setSelected(m_pref.general.showMenuBar());
+
+ showHome()->setSelected(m_pref.general.showHome());
+
+ // Right-click
+ rightClickBehavior()->setSelectedItemIndex((int)m_pref.editor.rightClickMode());
+
+ // Undo preferences
+ limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0);
+ onLimitUndoCheck();
+
+ undoGotoModified()->setSelected(m_pref.undo.gotoModified());
+ undoAllowNonlinearHistory()->setSelected(m_pref.undo.allowNonlinearHistory());
+
+ onChangeBgScope();
+ onChangeGridScope();
+ sectionListbox()->selectIndex(m_curSection);
}
bool ok() {
return (closer() == buttonOk());
}
- void saveConfig() {
+ void saveConfig(bool propagate = true) {
// Save preferences in widgets that are bound to options automatically
- {
+ if (propagate) {
Message msg(kSavePreferencesMessage);
msg.setPropagateToChildren(true);
sendMessage(&msg);
@@ -761,7 +777,7 @@ public:
int j = 2;
for (auto& cs : m_colorSpaces) {
// We add ICC profiles only
- auto gfxCs = cs->gfxColorSpace();
+ auto& gfxCs = cs->gfxColorSpace();
if (gfxCs->type() != gfx::ColorSpace::ICC)
continue;
@@ -899,9 +915,7 @@ public:
m_pref.general.showMenuBar(showMenuBar()->isSelected());
}
- bool newShowHome = showHome()->isSelected();
- if (newShowHome != m_pref.general.showHome())
- m_pref.general.showHome(newShowHome);
+ m_pref.general.showHome(showHome()->isSelected());
m_pref.save();
@@ -910,8 +924,7 @@ public:
}
// Probably it's safe to switch this flag in runtime
- if (m_pref.experimental.multipleWindows() != ui::get_multiple_displays())
- ui::set_multiple_displays(m_pref.experimental.multipleWindows());
+ ui::set_multiple_displays(m_pref.experimental.multipleWindows());
if (reset_screen)
updateScreenScaling();
@@ -934,6 +947,15 @@ public:
}
}
+ void restoreDefaultTheme() {
+ setUITheme(m_pref.theme.selected.defaultValue(), false);
+ m_pref.general.screenScale.setValue(
+ skin::SkinTheme::get(this)->preferredScreenScaling());
+ m_pref.general.uiScale.setValue(
+ skin::SkinTheme::get(this)->preferredUIScaling());
+ updateScreenScaling();
+ }
+
bool showDialogToInstallExtension(const std::string& filename) {
for (Widget* item : sectionListbox()->children()) {
if (auto listItem = dynamic_cast(item)) {
@@ -1043,6 +1065,133 @@ private:
m_restoreUIScaling = m_pref.general.uiScale();
}
+ void onResetDefault() {
+ if (ui::Alert::show(Strings::alerts_reset_default_confirm()) != 1)
+ return;
+
+ if (recentReset()->isSelected()) {
+ auto prevLimit = m_pref.general.recentItems();
+ App::instance()->recentFiles()->setLimit(0);
+ App::instance()->recentFiles()->setLimit(prevLimit);
+ }
+
+ if (installedReset()->isSelected()) {
+ // If we're not on the default theme, restore it, since we're gonna be deleting it.
+ restoreDefaultTheme();
+
+ // Load a list with the extensions we can uninstall first, to avoid iterator issues when deleting in-loop.
+ Extensions::List uninstall;
+ for (auto* e : App::instance()->extensions()) {
+ if (!e->canBeUninstalled())
+ continue;
+
+ uninstall.push_back(e);
+ }
+
+ for (auto* e : uninstall) {
+ try {
+ App::instance()->extensions().uninstallExtension(
+ e, DeletePluginPref::kYes);
+ }
+ catch (const std::exception& ex) {
+ LOG(ERROR, "Uninstalling extension '%s' failed with error '%s'\n",
+ e->displayName().c_str(),
+ ex.what());
+ Console::showException(ex);
+ }
+ }
+
+ ResourceFinder rf;
+ rf.includeUserDir("palettes");
+ const auto& paletteDir = rf.defaultFilename();
+ for (const auto& item : base::list_files(paletteDir)) {
+ const auto path = base::join_path(paletteDir, item);
+ if (base::is_file(path) &&
+ item != "default.ase" &&
+ base::string_to_lower(base::get_file_extension(path)) == "ase") {
+
+ try {
+ base::delete_file(path);
+ LOG(VERBOSE, "Deleted palette: '%s'\n", item.c_str());
+ }
+ catch (const std::exception& ex) {
+ LOG(ERROR,
+ "Error deleting palette file: %s - %s",
+ path.c_str(),
+ ex.what());
+ }
+ }
+ }
+ }
+
+ if (perfileReset()->isSelected()) {
+ ResourceFinder rf;
+ rf.includeUserDir("files");
+ const auto& filesDirectory = rf.defaultFilename();
+
+ for (const auto& item : base::list_files(filesDirectory)) {
+ const auto path = base::join_path(filesDirectory, item);
+ if (base::is_file(path) && base::string_to_lower(base::get_file_extension(path)) == "ini") {
+ try {
+ base::delete_file(path);
+ LOG(VERBOSE, "Deleted per-file setting '%s'\n", item.c_str());
+ }
+ catch (const std::exception& ex) {
+ LOG(ERROR,
+ "Error deleting ini file: %s - %s",
+ path.c_str(),
+ ex.what());
+ }
+ }
+ }
+ }
+
+ if (toolsReset()->isSelected()) {
+ auto* toolBox = App::instance()->toolBox();
+ for (tools::ToolIterator it = toolBox->begin(); it != toolBox->end(); ++it) {
+ tools::Tool* tool = *it;
+ m_pref.resetToolPreferences(tool);
+ LOG(VERBOSE, "Reset tool preferences for tool '%s'\n", tool->getId().c_str());
+ }
+ }
+
+ if (defaultReset()->isSelected()) {
+ onResetAlerts();
+ onResetBg();
+ onResetColorManagement();
+ onResetGrid();
+ onResetTimelineSel();
+
+ // If we're not on the default theme, restore it.
+ m_restoreThisTheme = m_pref.theme.selected.defaultValue();
+ restoreTheme();
+
+ // Resetting all things.
+ for (Section* section : m_pref.sectionList()) {
+ for (OptionBase* option : section->optionList()) {
+ option->resetToDefault();
+ }
+ section->save();
+ }
+
+ restoreDefaultTheme();
+
+ m_pref.save();
+ loadFromPreferences();
+
+ // Temporarily set the language preference to an empty string
+ // to avoid setCurrentLanguage ignoring the change.
+ m_pref.general.language("");
+ Strings::instance()->setCurrentLanguage(Strings::kDefLanguage);
+
+ // Language reset
+ refillLanguages();
+ }
+
+ saveConfig(false);
+ closeWindow(nullptr);
+ }
+
void onNativeCursorChange() {
bool state =
// If the platform supports custom cursors...
@@ -1133,11 +1282,11 @@ private:
int j = 2;
for (auto& cs : m_colorSpaces) {
// We add ICC profiles only
- auto gfxCs = cs->gfxColorSpace();
+ auto& gfxCs = cs->gfxColorSpace();
if (gfxCs->type() != gfx::ColorSpace::ICC)
continue;
- auto name = gfxCs->name();
+ auto& name = gfxCs->name();
windowCs()->addItem(fmt::format(m_templateTextForDisplayCS, name));
if (windowProfile == gen::WindowColorProfile::SPECIFIC &&
windowProfileName == name) {
diff --git a/src/app/pref/option.h b/src/app/pref/option.h
index beae70441..f4b3a1422 100644
--- a/src/app/pref/option.h
+++ b/src/app/pref/option.h
@@ -22,12 +22,15 @@ namespace app {
class Section {
public:
- Section(const std::string& name) : m_name(name) { }
- virtual ~Section() { }
+ explicit Section(const std::string& name) : m_name(name) { }
+ virtual ~Section() = default;
const char* name() const { return m_name.c_str(); }
virtual Section* section(const char* id) = 0;
virtual OptionBase* option(const char* id) = 0;
+ virtual std::vector optionList() const { return {}; }
+ virtual std::vector sectionList() const { return {}; }
+ virtual void save() = 0;
obs::signal BeforeChange;
obs::signal AfterChange;
@@ -42,9 +45,10 @@ namespace app {
: m_section(section)
, m_id(id) {
}
- virtual ~OptionBase() { }
+ virtual ~OptionBase() = default;
const char* section() const { return m_section->name(); }
const char* id() const { return m_id; }
+ virtual void resetToDefault() = 0;
#ifdef ENABLE_SCRIPTING
virtual void pushLua(lua_State* L) = 0;
@@ -127,6 +131,10 @@ namespace app {
m_dirty = false;
}
+ void resetToDefault() override {
+ setValue(m_default);
+ }
+
#ifdef ENABLE_SCRIPTING
void pushLua(lua_State* L) override {
script::push_value_to_lua(L, m_value);
diff --git a/src/app/pref/preferences.h b/src/app/pref/preferences.h
index 990709b0a..e0eeb8829 100644
--- a/src/app/pref/preferences.h
+++ b/src/app/pref/preferences.h
@@ -58,7 +58,7 @@ namespace app {
Preferences();
~Preferences();
- void save();
+ void save() override;
// Returns true if the given option was set by the user or false
// if it contains the default value.
diff --git a/src/app/ui/skin/skin_theme.h b/src/app/ui/skin/skin_theme.h
index 53eae6db5..070ea3486 100644
--- a/src/app/ui/skin/skin_theme.h
+++ b/src/app/ui/skin/skin_theme.h
@@ -59,8 +59,8 @@ namespace app {
~SkinTheme();
const std::string& path() { return m_path; }
- int preferredScreenScaling() { return m_preferredScreenScaling; }
- int preferredUIScaling() { return m_preferredUIScaling; }
+ int preferredScreenScaling() const { return m_preferredScreenScaling; }
+ int preferredUIScaling() const { return m_preferredUIScaling; }
os::Font* getDefaultFont() const override { return m_defaultFont.get(); }
os::Font* getWidgetFont(const ui::Widget* widget) const override;
diff --git a/src/gen/pref_types.cpp b/src/gen/pref_types.cpp
index 01365cb76..8e07c374d 100644
--- a/src/gen/pref_types.cpp
+++ b/src/gen/pref_types.cpp
@@ -28,7 +28,7 @@ static void print_pref_class_def(XMLElement* elem, const std::string& className,
<< "\n"
<< indent << "class " << className << " : public Section {\n"
<< indent << "public:\n"
- << indent << " " << className << "(const std::string& name);\n";
+ << indent << " explicit " << className << "(const std::string& name);\n";
if (elem->Attribute("canforce"))
std::cout << indent << " void forceSection();\n";
@@ -37,11 +37,15 @@ static void print_pref_class_def(XMLElement* elem, const std::string& className,
std::cout
<< indent << " void load();\n"
- << indent << " void save();\n"
+ << indent << " void save() override;\n"
<< indent << " Section* section(const char* id) override;\n"
<< indent << " OptionBase* option(const char* id) override;\n";
XMLElement* child = (elem->FirstChild() ? elem->FirstChild()->ToElement(): nullptr);
+
+ bool hasOptions = false;
+ bool hasSections = false;
+
while (child) {
if (child->Value()) {
std::string name = child->Value();
@@ -51,6 +55,7 @@ static void print_pref_class_def(XMLElement* elem, const std::string& className,
if (!child->Attribute("type")) throw std::runtime_error("missing 'type' attr in