#include "Settings.h" #include #include "model/FormatDefinitions.h" #include "util/DeviceListHelper.h" #include "ButtonConfig.h" #include "Util.h" #include "filesystem.h" #include "i18n.h" constexpr auto const* DEFAULT_FONT = "Sans"; constexpr auto DEFAULT_FONT_SIZE = 12; #define SAVE_BOOL_PROP(var) xmlNode = saveProperty((const char*)#var, (var) ? "true" : "false", root) #define SAVE_STRING_PROP(var) xmlNode = saveProperty((const char*)#var, (var).empty() ? "" : (var).c_str(), root) #define SAVE_INT_PROP(var) xmlNode = saveProperty((const char*)#var, var, root) #define SAVE_UINT_PROP(var) xmlNode = savePropertyUnsigned((const char*)#var, var, root) #define SAVE_DOUBLE_PROP(var) xmlNode = savePropertyDouble((const char*)#var, var, root) #define ATTACH_COMMENT(var) \ com = xmlNewComment((const xmlChar*)(var)); \ xmlAddPrevSibling(xmlNode, com); Settings::Settings(fs::path filepath): filepath(std::move(filepath)) { loadDefault(); } Settings::~Settings() { for (auto& i: this->buttonConfig) { delete i; i = nullptr; } } void Settings::loadDefault() { this->pressureSensitivity = true; this->minimumPressure = 0.05; this->pressureMultiplier = 1.0; this->pressureGuessing = false; this->zoomGesturesEnabled = true; this->maximized = false; this->showPairedPages = false; this->presentationMode = false; this->numColumns = 1; // only one of these applies at a time this->numRows = 1; this->viewFixedRows = false; this->layoutVertical = false; this->layoutRightToLeft = false; this->layoutBottomToTop = false; this->numPairsOffset = 1; this->zoomStep = 10.0; this->zoomStepScroll = 2.0; this->displayDpi = 72; this->font.setName(DEFAULT_FONT); this->font.setSize(DEFAULT_FONT_SIZE); this->mainWndWidth = 800; this->mainWndHeight = 600; this->showSidebar = true; this->sidebarWidth = 150; this->showToolbar = true; this->sidebarOnRight = false; this->scrollbarOnLeft = false; this->menubarVisible = true; this->autoloadPdfXoj = true; this->stylusCursorType = STYLUS_CURSOR_DOT; this->highlightPosition = false; this->cursorHighlightColor = 0x80FFFF00; // Yellow with 50% opacity this->cursorHighlightRadius = 30.0; this->cursorHighlightBorderColor = 0x800000FF; // Blue with 50% opacity this->cursorHighlightBorderWidth = 0.0; this->darkTheme = false; this->scrollbarHideType = SCROLLBAR_HIDE_NONE; this->disableScrollbarFadeout = false; // Set this for autosave frequency in minutes. this->autosaveTimeout = 3; this->autosaveEnabled = true; this->addHorizontalSpace = false; this->addHorizontalSpaceAmount = 150; this->addVerticalSpace = false; this->addVerticalSpaceAmount = 150; // Drawing direction emulates modifier keys this->drawDirModsRadius = 50; this->drawDirModsEnabled = false; this->snapRotation = true; this->snapRotationTolerance = 0.30; this->snapGrid = true; this->snapGridTolerance = 0.50; this->snapGridSize = DEFAULT_GRID_SIZE; this->touchDrawing = false; this->defaultSaveName = _("%F-Note-%H-%M"); // Eraser this->buttonConfig[BUTTON_ERASER] = new ButtonConfig(TOOL_ERASER, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Middle button this->buttonConfig[BUTTON_MOUSE_MIDDLE] = new ButtonConfig(TOOL_NONE, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Right button this->buttonConfig[BUTTON_MOUSE_RIGHT] = new ButtonConfig(TOOL_NONE, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Touch this->buttonConfig[BUTTON_TOUCH] = new ButtonConfig(TOOL_NONE, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Default config this->buttonConfig[BUTTON_DEFAULT] = new ButtonConfig(TOOL_PEN, Color{0x000000U}, TOOL_SIZE_FINE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Pen button 1 this->buttonConfig[BUTTON_STYLUS_ONE] = new ButtonConfig(TOOL_NONE, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); // Pen button 2 this->buttonConfig[BUTTON_STYLUS_TWO] = new ButtonConfig(TOOL_NONE, Color{0x000000U}, TOOL_SIZE_NONE, DRAWING_TYPE_DEFAULT, ERASER_TYPE_NONE); this->fullscreenHideElements = "mainMenubar"; this->presentationHideElements = "mainMenubar,sidebarContents"; this->touchZoomStartThreshold = 0.0; this->pageRerenderThreshold = 5.0; this->pdfPageCacheSize = 10; this->preloadPagesBefore = 3U; this->preloadPagesAfter = 5U; this->eagerPageCleanup = true; this->selectionBorderColor = 0xff0000U; // red this->selectionMarkerColor = 0x729fcfU; // light blue this->backgroundColor = 0xdcdad5U; // clang-format off this->pageTemplate = "xoj/template\ncopyLastPageSettings=true\nsize=595.275591x841.889764\nbackgroundType=lined\nbackgroundColor=#ffffff\n"; // clang-format on this->audioSampleRate = 44100.0; this->audioInputDevice = -1; this->audioOutputDevice = -1; this->audioGain = 1.0; this->defaultSeekTime = 5; this->pluginEnabled = ""; this->pluginDisabled = ""; this->numIgnoredStylusEvents = 0; this->inputSystemTPCButton = false; this->inputSystemDrawOutsideWindow = true; this->strokeFilterIgnoreTime = 150; this->strokeFilterIgnoreLength = 1; this->strokeFilterSuccessiveTime = 500; this->strokeFilterEnabled = false; this->doActionOnStrokeFiltered = false; this->trySelectOnStrokeFiltered = false; this->snapRecognizedShapesEnabled = false; this->restoreLineWidthEnabled = false; this->inTransaction = false; /** * Stabilizer related settings */ this->stabilizerAveragingMethod = StrokeStabilizer::AveragingMethod::NONE; this->stabilizerPreprocessor = StrokeStabilizer::Preprocessor::NONE; this->stabilizerBuffersize = 20; this->stabilizerSigma = 0.5; this->stabilizerDeadzoneRadius = 1.3; this->stabilizerCuspDetection = true; this->stabilizerDrag = 0.4; this->stabilizerMass = 5.0; this->stabilizerFinalizeStroke = true; /**/ } /** * tempg_ascii_strtod * Transition to using g_ascii_strtod to minimize disruption. May, 2019. * Delete this and replace calls to this function with calls to g_ascii_strtod() in 2020. * See: https://developer.gnome.org/glib/stable/glib-String-Utility-Functions.html#g-strtod */ auto tempg_ascii_strtod(const gchar* txt, gchar** endptr) -> double { return g_strtod(txt, endptr); // makes best guess between locale formatted and C formatted numbers. See link above. } void Settings::parseData(xmlNodePtr cur, SElement& elem) { for (xmlNodePtr x = cur->children; x != nullptr; x = x->next) { if (!xmlStrcmp(x->name, reinterpret_cast("data"))) { xmlChar* name = xmlGetProp(x, reinterpret_cast("name")); parseData(x, elem.child(reinterpret_cast(name))); xmlFree(name); } else if (!xmlStrcmp(x->name, reinterpret_cast("attribute"))) { xmlChar* name = xmlGetProp(x, reinterpret_cast("name")); xmlChar* value = xmlGetProp(x, reinterpret_cast("value")); xmlChar* type = xmlGetProp(x, reinterpret_cast("type")); string sType = reinterpret_cast(type); if (sType == "int") { int i = atoi(reinterpret_cast(value)); elem.setInt(reinterpret_cast(name), i); } else if (sType == "double") { double d = tempg_ascii_strtod(reinterpret_cast(value), nullptr); // g_ascii_strtod ignores locale setting. elem.setDouble(reinterpret_cast(name), d); } else if (sType == "hex") { int i = 0; if (sscanf(reinterpret_cast(value), "%x", &i)) { elem.setIntHex(reinterpret_cast(name), i); } else { g_warning("Settings::Unknown hex value: %s:%s\n", name, value); } } else if (sType == "string") { elem.setString(reinterpret_cast(name), reinterpret_cast(value)); } else if (sType == "boolean") { elem.setBool(reinterpret_cast(name), strcmp(reinterpret_cast(value), "true") == 0); } else { g_warning("Settings::Unknown datatype: %s\n", sType.c_str()); } xmlFree(name); xmlFree(type); xmlFree(value); } else { g_warning("Settings::parseData: Unknown XML node: %s\n", x->name); continue; } } } void Settings::parseItem(xmlDocPtr doc, xmlNodePtr cur) { // Parse data map if (!xmlStrcmp(cur->name, reinterpret_cast("data"))) { xmlChar* name = xmlGetProp(cur, reinterpret_cast("name")); if (name == nullptr) { g_warning("Settings::%s:No name property!\n", cur->name); return; } parseData(cur, data[reinterpret_cast(name)]); xmlFree(name); return; } if (cur->type == XML_COMMENT_NODE) { return; } if (xmlStrcmp(cur->name, reinterpret_cast("property"))) { g_warning("Settings::Unknown XML node: %s\n", cur->name); return; } xmlChar* name = xmlGetProp(cur, reinterpret_cast("name")); if (name == nullptr) { g_warning("Settings::%s:No name property!\n", cur->name); return; } if (xmlStrcmp(name, reinterpret_cast("font")) == 0) { xmlFree(name); xmlChar* font = nullptr; xmlChar* size = nullptr; font = xmlGetProp(cur, reinterpret_cast("font")); if (font) { this->font.setName(reinterpret_cast(font)); xmlFree(font); } size = xmlGetProp(cur, reinterpret_cast("size")); if (size) { double dSize = DEFAULT_FONT_SIZE; if (sscanf(reinterpret_cast(size), "%lf", &dSize) == 1) { this->font.setSize(dSize); } xmlFree(size); } return; } xmlChar* value = xmlGetProp(cur, reinterpret_cast("value")); if (value == nullptr) { xmlFree(name); g_warning("No value property!\n"); return; } // TODO(fabian): remove this typo fix in 2-3 release cycles if (xmlStrcmp(name, reinterpret_cast("presureSensitivity")) == 0) { this->pressureSensitivity = xmlStrcmp(value, reinterpret_cast("true")) == 0; } if (xmlStrcmp(name, reinterpret_cast("pressureSensitivity")) == 0) { this->pressureSensitivity = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("minimumPressure")) == 0) { this->minimumPressure = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("pressureMultiplier")) == 0) { this->pressureMultiplier = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("zoomGesturesEnabled")) == 0) { this->zoomGesturesEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("selectedToolbar")) == 0) { this->selectedToolbar = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("lastSavePath")) == 0) { this->lastSavePath = fs::u8path(reinterpret_cast(value)); } else if (xmlStrcmp(name, reinterpret_cast("lastOpenPath")) == 0) { this->lastOpenPath = fs::u8path(reinterpret_cast(value)); } else if (xmlStrcmp(name, reinterpret_cast("lastImagePath")) == 0) { this->lastImagePath = fs::u8path(reinterpret_cast(value)); } else if (xmlStrcmp(name, reinterpret_cast("zoomStep")) == 0) { this->zoomStep = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("zoomStepScroll")) == 0) { this->zoomStepScroll = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("displayDpi")) == 0) { this->displayDpi = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("mainWndWidth")) == 0) { this->mainWndWidth = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("mainWndHeight")) == 0) { this->mainWndHeight = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("maximized")) == 0) { this->maximized = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("showToolbar")) == 0) { this->showToolbar = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("showSidebar")) == 0) { this->showSidebar = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("sidebarWidth")) == 0) { this->sidebarWidth = std::max(g_ascii_strtoll(reinterpret_cast(value), nullptr, 10), 50); } else if (xmlStrcmp(name, reinterpret_cast("sidebarOnRight")) == 0) { this->sidebarOnRight = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("scrollbarOnLeft")) == 0) { this->scrollbarOnLeft = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("menubarVisible")) == 0) { this->menubarVisible = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("numColumns")) == 0) { this->numColumns = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("numRows")) == 0) { this->numRows = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("viewFixedRows")) == 0) { this->viewFixedRows = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("layoutVertical")) == 0) { this->layoutVertical = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("layoutRightToLeft")) == 0) { this->layoutRightToLeft = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("layoutBottomToTop")) == 0) { this->layoutBottomToTop = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("showPairedPages")) == 0) { this->showPairedPages = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("numPairsOffset")) == 0) { this->numPairsOffset = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("presentationMode")) == 0) { this->presentationMode = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("autoloadPdfXoj")) == 0) { this->autoloadPdfXoj = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("stylusCursorType")) == 0) { this->stylusCursorType = stylusCursorTypeFromString(reinterpret_cast(value)); } else if (xmlStrcmp(name, reinterpret_cast("highlightPosition")) == 0) { this->highlightPosition = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("cursorHighlightColor")) == 0) { this->cursorHighlightColor = g_ascii_strtoull(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("cursorHighlightRadius")) == 0) { this->cursorHighlightRadius = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("cursorHighlightBorderColor")) == 0) { this->cursorHighlightBorderColor = g_ascii_strtoull(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("cursorHighlightBorderWidth")) == 0) { this->cursorHighlightBorderWidth = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("darkTheme")) == 0) { this->darkTheme = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("defaultSaveName")) == 0) { this->defaultSaveName = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("pluginEnabled")) == 0) { this->pluginEnabled = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("pluginDisabled")) == 0) { this->pluginDisabled = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("pageTemplate")) == 0) { this->pageTemplate = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("sizeUnit")) == 0) { this->sizeUnit = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("audioFolder")) == 0) { this->audioFolder = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("autosaveEnabled")) == 0) { this->autosaveEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("autosaveTimeout")) == 0) { this->autosaveTimeout = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("fullscreenHideElements")) == 0) { this->fullscreenHideElements = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("presentationHideElements")) == 0) { this->presentationHideElements = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("touchZoomStartThreshold")) == 0) { this->touchZoomStartThreshold = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("pageRerenderThreshold")) == 0) { this->pageRerenderThreshold = g_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("pdfPageCacheSize")) == 0) { this->pdfPageCacheSize = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("preloadPagesBefore")) == 0) { this->preloadPagesBefore = g_ascii_strtoull(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("preloadPagesAfter")) == 0) { this->preloadPagesAfter = g_ascii_strtoull(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("eagerPageCleanup")) == 0) { this->eagerPageCleanup = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("selectionBorderColor")) == 0) { this->selectionBorderColor = Color(g_ascii_strtoull(reinterpret_cast(value), nullptr, 10)); } else if (xmlStrcmp(name, reinterpret_cast("selectionMarkerColor")) == 0) { this->selectionMarkerColor = Color(g_ascii_strtoull(reinterpret_cast(value), nullptr, 10)); } else if (xmlStrcmp(name, reinterpret_cast("backgroundColor")) == 0) { this->backgroundColor = Color(g_ascii_strtoull(reinterpret_cast(value), nullptr, 10)); } else if (xmlStrcmp(name, reinterpret_cast("addHorizontalSpace")) == 0) { this->addHorizontalSpace = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("addHorizontalSpaceAmount")) == 0) { this->addHorizontalSpaceAmount = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("addVerticalSpace")) == 0) { this->addVerticalSpace = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("addVerticalSpaceAmount")) == 0) { this->addVerticalSpaceAmount = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("drawDirModsEnabled")) == 0) { this->drawDirModsEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("drawDirModsRadius")) == 0) { this->drawDirModsRadius = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("snapRotation")) == 0) { this->snapRotation = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("snapRotationTolerance")) == 0) { this->snapRotationTolerance = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("snapGrid")) == 0) { this->snapGrid = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("snapGridSize")) == 0) { this->snapGridSize = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("snapGridTolerance")) == 0) { this->snapGridTolerance = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("touchDrawing")) == 0) { this->touchDrawing = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("pressureGuessing")) == 0) { this->pressureGuessing = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("scrollbarHideType")) == 0) { if (xmlStrcmp(value, reinterpret_cast("both")) == 0) { this->scrollbarHideType = SCROLLBAR_HIDE_BOTH; } else if (xmlStrcmp(value, reinterpret_cast("horizontal")) == 0) { this->scrollbarHideType = SCROLLBAR_HIDE_HORIZONTAL; } else if (xmlStrcmp(value, reinterpret_cast("vertical")) == 0) { this->scrollbarHideType = SCROLLBAR_HIDE_VERTICAL; } else { this->scrollbarHideType = SCROLLBAR_HIDE_NONE; } } else if (xmlStrcmp(name, reinterpret_cast("disableScrollbarFadeout")) == 0) { this->disableScrollbarFadeout = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("audioSampleRate")) == 0) { this->audioSampleRate = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("audioGain")) == 0) { this->audioGain = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("defaultSeekTime")) == 0) { this->defaultSeekTime = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("audioInputDevice")) == 0) { this->audioInputDevice = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("audioOutputDevice")) == 0) { this->audioOutputDevice = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("numIgnoredStylusEvents")) == 0) { this->numIgnoredStylusEvents = std::max(g_ascii_strtoll(reinterpret_cast(value), nullptr, 10), 0); } else if (xmlStrcmp(name, reinterpret_cast("inputSystemTPCButton")) == 0) { this->inputSystemTPCButton = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("inputSystemDrawOutsideWindow")) == 0) { this->inputSystemDrawOutsideWindow = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("strokeFilterIgnoreTime")) == 0) { this->strokeFilterIgnoreTime = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("strokeFilterIgnoreLength")) == 0) { this->strokeFilterIgnoreLength = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("strokeFilterSuccessiveTime")) == 0) { this->strokeFilterSuccessiveTime = g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("strokeFilterEnabled")) == 0) { this->strokeFilterEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("doActionOnStrokeFiltered")) == 0) { this->doActionOnStrokeFiltered = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("trySelectOnStrokeFiltered")) == 0) { this->trySelectOnStrokeFiltered = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("latexSettings.autoCheckDependencies")) == 0) { this->latexSettings.autoCheckDependencies = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("latexSettings.globalTemplatePath")) == 0) { std::string v(reinterpret_cast(value)); this->latexSettings.globalTemplatePath = fs::u8path(v); } else if (xmlStrcmp(name, reinterpret_cast("latexSettings.genCmd")) == 0) { this->latexSettings.genCmd = reinterpret_cast(value); } else if (xmlStrcmp(name, reinterpret_cast("snapRecognizedShapesEnabled")) == 0) { this->snapRecognizedShapesEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("restoreLineWidthEnabled")) == 0) { this->restoreLineWidthEnabled = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("preferredLocale")) == 0) { this->preferredLocale = reinterpret_cast(value); /** * Stabilizer related settings */ } else if (xmlStrcmp(name, reinterpret_cast("stabilizerAveragingMethod")) == 0) { this->stabilizerAveragingMethod = (StrokeStabilizer::AveragingMethod)g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerPreprocessor")) == 0) { this->stabilizerPreprocessor = (StrokeStabilizer::Preprocessor)g_ascii_strtoll(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerBuffersize")) == 0) { this->stabilizerBuffersize = g_ascii_strtoull(reinterpret_cast(value), nullptr, 10); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerSigma")) == 0) { this->stabilizerSigma = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerDeadzoneRadius")) == 0) { this->stabilizerDeadzoneRadius = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerDrag")) == 0) { this->stabilizerDrag = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerMass")) == 0) { this->stabilizerMass = tempg_ascii_strtod(reinterpret_cast(value), nullptr); } else if (xmlStrcmp(name, reinterpret_cast("stabilizerCuspDetection")) == 0) { this->stabilizerCuspDetection = xmlStrcmp(value, reinterpret_cast("true")) == 0; } else if (xmlStrcmp(name, reinterpret_cast("stabilizerFinalizeStroke")) == 0) { this->stabilizerFinalizeStroke = xmlStrcmp(value, reinterpret_cast("true")) == 0; } /**/ xmlFree(name); xmlFree(value); } void Settings::loadDeviceClasses() { SElement& s = getCustomElement("deviceClasses"); for (auto device: s.children()) { SElement& deviceNode = device.second; int deviceClass = 0; int deviceSource = 0; deviceNode.getInt("deviceClass", deviceClass); deviceNode.getInt("deviceSource", deviceSource); inputDeviceClasses.emplace(device.first, std::make_pair(static_cast(deviceClass), static_cast(deviceSource))); } } void Settings::loadButtonConfig() { SElement& s = getCustomElement("buttonConfig"); for (int i = 0; i < BUTTON_COUNT; i++) { SElement& e = s.child(buttonToString(static_cast