diff --git a/src/graphicswin.cpp b/src/graphicswin.cpp index 6e67415..f08eea7 100644 --- a/src/graphicswin.cpp +++ b/src/graphicswin.cpp @@ -283,7 +283,7 @@ void GraphicsWindow::PopulateMainMenu() { for(const Locale &locale : Locales()) { localeMenu->AddItem(locale.displayName, [&]() { SetLocale(locale.Culture()); - CnfFreezeString(locale.Culture(), "Locale"); + Platform::GetSettings()->FreezeString("Locale", locale.Culture()); SS.UpdateWindowTitles(); PopulateMainMenu(); diff --git a/src/lib.cpp b/src/lib.cpp index 4e5e7fd..4ebaa1f 100644 --- a/src/lib.cpp +++ b/src/lib.cpp @@ -17,17 +17,6 @@ void Group::GenerateEquations(IdList *) { // Nothing to do for now. } -void SolveSpace::CnfFreezeInt(uint32_t, const std::string &) -{ - abort(); -} - -uint32_t SolveSpace::CnfThawInt(uint32_t, const std::string &) -{ - abort(); - return 0; -} - void SolveSpace::DoMessageBox(const char *, int, int, bool) { abort(); diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index 77ef7da..cd9f7cd 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -19,49 +19,6 @@ static NSString* Wrap(const std::string &s) { return [NSString stringWithUTF8String:s.c_str()]; } -/* Settings */ - -namespace SolveSpace { -void CnfFreezeInt(uint32_t val, const std::string &key) { - [[NSUserDefaults standardUserDefaults] - setInteger:val forKey:Wrap(key)]; -} - -uint32_t CnfThawInt(uint32_t val, const std::string &key) { - NSString *nsKey = Wrap(key); - if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) - return [[NSUserDefaults standardUserDefaults] integerForKey:nsKey]; - return val; -} - -void CnfFreezeFloat(float val, const std::string &key) { - [[NSUserDefaults standardUserDefaults] - setFloat:val forKey:Wrap(key)]; -} - -float CnfThawFloat(float val, const std::string &key) { - NSString *nsKey = Wrap(key); - if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) - return [[NSUserDefaults standardUserDefaults] floatForKey:nsKey]; - return val; -} - -void CnfFreezeString(const std::string &val, const std::string &key) { - [[NSUserDefaults standardUserDefaults] - setObject:Wrap(val) - forKey:Wrap(key)]; -} - -std::string CnfThawString(const std::string &val, const std::string &key) { - NSString *nsKey = Wrap(key); - if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) { - NSString *nsNewVal = [[NSUserDefaults standardUserDefaults] stringForKey:nsKey]; - return [nsNewVal UTF8String]; - } - return val; -} -}; - /* Save/load */ bool SolveSpace::GetOpenFile(Platform::Path *filename, const std::string &defExtension, diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index 2ab8e93..fb05ccd 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -57,111 +57,6 @@ std::string Title(const std::string &s) { return "SolveSpace - " + s; } -/* Settings */ - -/* Why not just use GSettings? Two reasons. It doesn't allow to easily see - whether the setting had the default value, and it requires to install - a schema globally. */ -static json_object *settings = NULL; - -static std::string CnfPrepare() { - // Refer to http://standards.freedesktop.org/basedir-spec/latest/ - - std::string dir; - if(getenv("XDG_CONFIG_HOME")) { - dir = std::string(getenv("XDG_CONFIG_HOME")) + "/solvespace"; - } else if(getenv("HOME")) { - dir = std::string(getenv("HOME")) + "/.config/solvespace"; - } else { - dbp("neither XDG_CONFIG_HOME nor HOME are set"); - return ""; - } - - struct stat st; - if(stat(dir.c_str(), &st)) { - if(errno == ENOENT) { - if(mkdir(dir.c_str(), 0777)) { - dbp("cannot mkdir %s: %s", dir.c_str(), strerror(errno)); - return ""; - } - } else { - dbp("cannot stat %s: %s", dir.c_str(), strerror(errno)); - return ""; - } - } else if(!S_ISDIR(st.st_mode)) { - dbp("%s is not a directory", dir.c_str()); - return ""; - } - - return dir + "/settings.json"; -} - -static void CnfLoad() { - std::string path = CnfPrepare(); - if(path.empty()) - return; - - if(settings) - json_object_put(settings); // deallocate - - settings = json_object_from_file(path.c_str()); - if(!settings) { - if(errno != ENOENT) - dbp("cannot load settings: %s", strerror(errno)); - - settings = json_object_new_object(); - } -} - -static void CnfSave() { - std::string path = CnfPrepare(); - if(path.empty()) - return; - - /* json-c <0.12 has the first argument non-const here */ - if(json_object_to_file_ext((char*) path.c_str(), settings, JSON_C_TO_STRING_PRETTY)) - dbp("cannot save settings: %s", strerror(errno)); -} - -void CnfFreezeInt(uint32_t val, const std::string &key) { - struct json_object *jval = json_object_new_int(val); - json_object_object_add(settings, key.c_str(), jval); - CnfSave(); -} - -uint32_t CnfThawInt(uint32_t val, const std::string &key) { - struct json_object *jval; - if(json_object_object_get_ex(settings, key.c_str(), &jval)) - return json_object_get_int(jval); - else return val; -} - -void CnfFreezeFloat(float val, const std::string &key) { - struct json_object *jval = json_object_new_double(val); - json_object_object_add(settings, key.c_str(), jval); - CnfSave(); -} - -float CnfThawFloat(float val, const std::string &key) { - struct json_object *jval; - if(json_object_object_get_ex(settings, key.c_str(), &jval)) - return json_object_get_double(jval); - else return val; -} - -void CnfFreezeString(const std::string &val, const std::string &key) { - struct json_object *jval = json_object_new_string(val.c_str()); - json_object_object_add(settings, key.c_str(), jval); - CnfSave(); -} - -std::string CnfThawString(const std::string &val, const std::string &key) { - struct json_object *jval; - if(json_object_object_get_ex(settings, key.c_str(), &jval)) - return json_object_get_string(jval); - return val; -} - /* Save/load */ static std::string ConvertFilters(std::string active, const FileFilter ssFilters[], @@ -202,12 +97,12 @@ bool GetOpenFile(Platform::Path *filename, const std::string &activeOrEmpty, chooser.set_filename(filename->raw); chooser.add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL); chooser.add_button(_("_Open"), Gtk::RESPONSE_OK); - chooser.set_current_folder(CnfThawString("", "FileChooserPath")); + chooser.set_current_folder(Platform::GetSettings()->ThawString("FileChooserPath")); ConvertFilters(activeOrEmpty, filters, &chooser); if(chooser.run() == Gtk::RESPONSE_OK) { - CnfFreezeString(chooser.get_current_folder(), "FileChooserPath"); + Platform::GetSettings()->FreezeString("FileChooserPath", chooser.get_current_folder()); *filename = Platform::Path::From(chooser.get_filename()); return true; } else { @@ -250,7 +145,7 @@ bool GetSaveFile(Platform::Path *filename, const std::string &defExtension, std::string activeExtension = ConvertFilters(defExtension, filters, &chooser); if(filename->IsEmpty()) { - chooser.set_current_folder(CnfThawString("", "FileChooserPath")); + chooser.set_current_folder(Platform::GetSettings()->ThawString("FileChooserPath")); chooser.set_current_name(std::string(_("untitled")) + "." + activeExtension); } else { chooser.set_current_folder(filename->Parent().raw); @@ -263,7 +158,7 @@ bool GetSaveFile(Platform::Path *filename, const std::string &defExtension, connect(sigc::bind(sigc::ptr_fun(&ChooserFilterChanged), &chooser)); if(chooser.run() == Gtk::RESPONSE_OK) { - CnfFreezeString(chooser.get_current_folder(), "FileChooserPath"); + Platform::GetSettings()->FreezeString("FileChooserPath", chooser.get_current_folder()); *filename = Platform::Path::From(chooser.get_filename()); return true; } else { @@ -458,8 +353,6 @@ int main(int argc, char** argv) { gdk_window_add_filter(NULL, GdkSpnavFilter, NULL); #endif - CnfLoad(); - const char* const* langNames = g_get_language_names(); while(*langNames) { if(SetLocale(*langNames++)) break; diff --git a/src/platform/gui.cpp b/src/platform/gui.cpp index cbcca47..0d7faca 100644 --- a/src/platform/gui.cpp +++ b/src/platform/gui.cpp @@ -8,6 +8,10 @@ namespace SolveSpace { namespace Platform { +//----------------------------------------------------------------------------- +// Keyboard events +//----------------------------------------------------------------------------- + std::string AcceleratorDescription(const KeyboardEvent &accel) { std::string label; if(accel.controlDown) { @@ -45,5 +49,25 @@ std::string AcceleratorDescription(const KeyboardEvent &accel) { return label; } +//----------------------------------------------------------------------------- +// Settings +//----------------------------------------------------------------------------- + +void Settings::FreezeBool(const std::string &key, bool value) { + FreezeInt(key, (int)value); +} + +bool Settings::ThawBool(const std::string &key, bool defaultValue) { + return (bool)ThawInt(key, (int)defaultValue); +} + +void Settings::FreezeColor(const std::string &key, RgbaColor value) { + FreezeInt(key, value.ToPackedInt()); +} + +RgbaColor Settings::ThawColor(const std::string &key, RgbaColor defaultValue) { + return RgbaColor::FromPackedInt(ThawInt(key, defaultValue.ToPackedInt())); +} + } } diff --git a/src/platform/gui.h b/src/platform/gui.h index 81a6306..9be2753 100644 --- a/src/platform/gui.h +++ b/src/platform/gui.h @@ -76,6 +76,32 @@ std::string AcceleratorDescription(const KeyboardEvent &accel); // Interfaces //----------------------------------------------------------------------------- +// A native settings store. +class Settings { +public: + virtual ~Settings() {} + + virtual void FreezeInt(const std::string &key, uint32_t value) = 0; + virtual uint32_t ThawInt(const std::string &key, uint32_t defaultValue = 0) = 0; + + virtual void FreezeFloat(const std::string &key, double value) = 0; + virtual double ThawFloat(const std::string &key, double defaultValue = 0.0) = 0; + + virtual void FreezeString(const std::string &key, const std::string &value) = 0; + virtual std::string ThawString(const std::string &key, + const std::string &defaultValue = "") = 0; + + virtual void FreezeBool(const std::string &key, bool value); + virtual bool ThawBool(const std::string &key, bool defaultValue = false); + + virtual void FreezeColor(const std::string &key, RgbaColor value); + virtual RgbaColor ThawColor(const std::string &key, RgbaColor defaultValue); +}; + +typedef std::shared_ptr SettingsRef; + +SettingsRef GetSettings(); + // A native single-shot timer. class Timer { public: @@ -191,8 +217,8 @@ public: virtual void GetContentSize(double *width, double *height) = 0; virtual void SetMinContentSize(double width, double height) = 0; - virtual void FreezePosition(const std::string &key) = 0; - virtual void ThawPosition(const std::string &key) = 0; + virtual void FreezePosition(SettingsRef settings, const std::string &key) = 0; + virtual void ThawPosition(SettingsRef settings, const std::string &key) = 0; virtual void SetCursor(Cursor cursor) = 0; virtual void SetTooltip(const std::string &text) = 0; diff --git a/src/platform/guigtk.cpp b/src/platform/guigtk.cpp index cbd3bd1..bb47de8 100644 --- a/src/platform/guigtk.cpp +++ b/src/platform/guigtk.cpp @@ -4,6 +4,11 @@ // Copyright 2018 whitequark //----------------------------------------------------------------------------- #include "solvespace.h" +#include +#include +#include +#include +#include #include #include #include @@ -20,6 +25,128 @@ namespace SolveSpace { namespace Platform { +//----------------------------------------------------------------------------- +// Settings +//----------------------------------------------------------------------------- + +class SettingsImplGtk : public Settings { +public: + // Why aren't we using GSettings? Two reasons. It doesn't allow to easily see whether + // the setting had the default value, and it requires to install a schema globally. + Path _path; + json_object *_json = NULL; + + static Path GetConfigPath() { + Path configHome; + if(getenv("XDG_CONFIG_HOME")) { + configHome = Path::From(getenv("XDG_CONFIG_HOME")); + } else if(getenv("HOME")) { + configHome = Path::From(getenv("HOME")).Join(".config"); + } else { + dbp("neither XDG_CONFIG_HOME nor HOME are set"); + return Path::From(""); + } + if(!configHome.IsEmpty()) { + configHome = configHome.Join("solvespace"); + } + + const char *configHomeC = configHome.raw.c_str(); + struct stat st; + if(stat(configHomeC, &st)) { + if(errno == ENOENT) { + if(mkdir(configHomeC, 0777)) { + dbp("cannot mkdir %s: %s", configHomeC, strerror(errno)); + return Path::From(""); + } + } else { + dbp("cannot stat %s: %s", configHomeC, strerror(errno)); + return Path::From(""); + } + } else if(!S_ISDIR(st.st_mode)) { + dbp("%s is not a directory", configHomeC); + return Path::From(""); + } + + return configHome.Join("settings.json"); + } + + SettingsImplGtk() { + _path = GetConfigPath(); + if(_path.IsEmpty()) { + dbp("settings will not be saved"); + } else { + _json = json_object_from_file(_path.raw.c_str()); + if(!_json && errno != ENOENT) { + dbp("cannot load settings: %s", strerror(errno)); + } + } + + if(_json == NULL) { + _json = json_object_new_object(); + } + } + + ~SettingsImplGtk() { + if(!_path.IsEmpty()) { + // json-c <0.12 has the first argument non-const + if(json_object_to_file_ext((char *)_path.raw.c_str(), _json, + JSON_C_TO_STRING_PRETTY)) { + dbp("cannot save settings: %s", strerror(errno)); + } + } + + json_object_put(_json); + } + + void FreezeInt(const std::string &key, uint32_t value) override { + struct json_object *jsonValue = json_object_new_int(value); + json_object_object_add(_json, key.c_str(), jsonValue); + } + + uint32_t ThawInt(const std::string &key, uint32_t defaultValue) override { + struct json_object *jsonValue; + if(json_object_object_get_ex(_json, key.c_str(), &jsonValue)) { + return json_object_get_int(jsonValue); + } + return defaultValue; + } + + void FreezeFloat(const std::string &key, double value) override { + struct json_object *jsonValue = json_object_new_double(value); + json_object_object_add(_json, key.c_str(), jsonValue); + } + + double ThawFloat(const std::string &key, double defaultValue) override { + struct json_object *jsonValue; + if(json_object_object_get_ex(_json, key.c_str(), &jsonValue)) { + return json_object_get_double(jsonValue); + } + return defaultValue; + } + + void FreezeString(const std::string &key, const std::string &value) override { + struct json_object *jsonValue = json_object_new_string(value.c_str()); + json_object_object_add(_json, key.c_str(), jsonValue); + } + + std::string ThawString(const std::string &key, + const std::string &defaultValue = "") override { + struct json_object *jsonValue; + if(json_object_object_get_ex(_json, key.c_str(), &jsonValue)) { + return json_object_get_string(jsonValue); + } + return defaultValue; + } +}; + +SettingsRef GetSettings() { + static std::shared_ptr settings; + if(!settings) { + settings = std::make_shared(); + } + return settings; +} + //----------------------------------------------------------------------------- // Timers //----------------------------------------------------------------------------- @@ -721,7 +848,7 @@ public: gtkWindow.get_gl_widget().set_size_request(width, height); } - void FreezePosition(const std::string &key) override { + void FreezePosition(SettingsRef settings, const std::string &key) override { if(!gtkWindow.is_visible()) return; int left, top, width, height; @@ -729,27 +856,27 @@ public: gtkWindow.get_size(width, height); bool isMaximized = gtkWindow.is_maximized(); - CnfFreezeInt(left, key + "_left"); - CnfFreezeInt(top, key + "_top"); - CnfFreezeInt(width, key + "_width"); - CnfFreezeInt(height, key + "_height"); - CnfFreezeInt(isMaximized, key + "_maximized"); + settings->FreezeInt(key + "_Left", left); + settings->FreezeInt(key + "_Top", top); + settings->FreezeInt(key + "_Width", width); + settings->FreezeInt(key + "_Height", height); + settings->FreezeBool(key + "_Maximized", isMaximized); } - void ThawPosition(const std::string &key) override { + void ThawPosition(SettingsRef settings, const std::string &key) override { int left, top, width, height; gtkWindow.get_position(left, top); gtkWindow.get_size(width, height); - left = CnfThawInt(left, key + "_left"); - top = CnfThawInt(top, key + "_top"); - width = CnfThawInt(width, key + "_width"); - height = CnfThawInt(height, key + "_height"); + left = settings->ThawInt(key + "_Left", left); + top = settings->ThawInt(key + "_Top", top); + width = settings->ThawInt(key + "_Width", width); + height = settings->ThawInt(key + "_Height", height); gtkWindow.move(left, top); gtkWindow.resize(width, height); - if(CnfThawInt(false, key + "_maximized")) { + if(settings->ThawBool(key + "_Maximized", false)) { gtkWindow.maximize(); } } diff --git a/src/platform/guimac.mm b/src/platform/guimac.mm index 7b04d68..3c4fbdd 100644 --- a/src/platform/guimac.mm +++ b/src/platform/guimac.mm @@ -52,6 +52,72 @@ static NSString* Wrap(const std::string &s) { namespace SolveSpace { namespace Platform { +//----------------------------------------------------------------------------- +// Settings +//----------------------------------------------------------------------------- + +class SettingsImplCocoa : public Settings { +public: + NSUserDefaults *userDefaults; + + SettingsImplCocoa() { + userDefaults = [NSUserDefaults standardUserDefaults]; + } + + void FreezeInt(const std::string &key, uint32_t value) override { + [userDefaults setInteger:value forKey:Wrap(key)]; + } + + uint32_t ThawInt(const std::string &key, uint32_t defaultValue = 0) override { + NSString *nsKey = Wrap(key); + if([userDefaults objectForKey:nsKey]) { + return [userDefaults integerForKey:nsKey]; + } + return defaultValue; + } + + void FreezeBool(const std::string &key, bool value) override { + [userDefaults setBool:value forKey:Wrap(key)]; + } + + bool ThawBool(const std::string &key, bool defaultValue = false) override { + NSString *nsKey = Wrap(key); + if([userDefaults objectForKey:nsKey]) { + return [userDefaults boolForKey:nsKey]; + } + return defaultValue; + } + + void FreezeFloat(const std::string &key, double value) override { + [userDefaults setDouble:value forKey:Wrap(key)]; + } + + double ThawFloat(const std::string &key, double defaultValue = 0.0) override { + NSString *nsKey = Wrap(key); + if([userDefaults objectForKey:nsKey]) { + return [userDefaults doubleForKey:nsKey]; + } + return defaultValue; + } + + void FreezeString(const std::string &key, const std::string &value) override { + [userDefaults setObject:Wrap(value) forKey:Wrap(key)]; + } + + std::string ThawString(const std::string &key, + const std::string &defaultValue = "") override { + NSObject *nsValue = [userDefaults objectForKey:Wrap(key)]; + if(nsValue && [nsValue isKindOfClass:[NSString class]]) { + return [(NSString *)nsValue UTF8String]; + } + return defaultValue; + } +}; + +SettingsRef GetSettings() { + return std::make_shared(); +} + //----------------------------------------------------------------------------- // Timers //----------------------------------------------------------------------------- @@ -805,11 +871,11 @@ public: [nsWindow setContentSize:nsMinSize]; } - void FreezePosition(const std::string &key) override { + void FreezePosition(SettingsRef _settings, const std::string &key) override { [nsWindow saveFrameUsingName:Wrap(key)]; } - void ThawPosition(const std::string &key) override { + void ThawPosition(SettingsRef _settings, const std::string &key) override { [nsWindow setFrameUsingName:Wrap(key)]; } diff --git a/src/platform/guinone.cpp b/src/platform/guinone.cpp index 71385f4..67d9c1e 100644 --- a/src/platform/guinone.cpp +++ b/src/platform/guinone.cpp @@ -18,6 +18,38 @@ std::shared_ptr CreateRenderer() { namespace Platform { +//----------------------------------------------------------------------------- +// Settings +//----------------------------------------------------------------------------- + +class SettingsImplDummy : public Settings { +public: + void FreezeInt(const std::string &key, uint32_t value) {} + + uint32_t ThawInt(const std::string &key, uint32_t defaultValue = 0) { + return defaultValue; + } + + void FreezeFloat(const std::string &key, double value) {} + + double ThawFloat(const std::string &key, double defaultValue = 0.0) { + return defaultValue; + } + + void FreezeString(const std::string &key, const std::string &value) {} + + std::string ThawString(const std::string &key, + const std::string &defaultValue = "") { + return defaultValue; + } +}; + +SettingsRef GetSettings() { + static std::shared_ptr settings = + std::make_shared(); + return settings; +} + //----------------------------------------------------------------------------- // Timers //----------------------------------------------------------------------------- @@ -62,76 +94,6 @@ void Exit() { } -//----------------------------------------------------------------------------- -// Settings -//----------------------------------------------------------------------------- - -class Setting { -public: - enum class Type { - Undefined, - Int, - Float, - String - }; - - Type type; - int valueInt; - float valueFloat; - std::string valueString; - - void CheckType(Type expectedType) { - ssassert(type == Setting::Type::Undefined || - type == expectedType, "Wrong setting type"); - type = expectedType; - } -}; - -std::map settings; - -void CnfFreezeInt(uint32_t val, const std::string &key) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::Int); - setting.valueInt = val; -} -uint32_t CnfThawInt(uint32_t val, const std::string &key) { - if(settings.find(key) != settings.end()) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::Int); - val = setting.valueInt; - } - return val; -} - -void CnfFreezeFloat(float val, const std::string &key) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::Float); - setting.valueFloat = val; -} -float CnfThawFloat(float val, const std::string &key) { - if(settings.find(key) != settings.end()) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::Float); - val = setting.valueFloat; - } - return val; -} - -void CnfFreezeString(const std::string &val, const std::string &key) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::String); - setting.valueString = val; -} -std::string CnfThawString(const std::string &val, const std::string &key) { - std::string ret = val; - if(settings.find(key) != settings.end()) { - Setting &setting = settings[key]; - setting.CheckType(Setting::Type::String); - ret = setting.valueString; - } - return ret; -} - //----------------------------------------------------------------------------- // Dialogs //----------------------------------------------------------------------------- diff --git a/src/platform/guiwin.cpp b/src/platform/guiwin.cpp index 1997450..2918b1d 100644 --- a/src/platform/guiwin.cpp +++ b/src/platform/guiwin.cpp @@ -102,6 +102,87 @@ static int Clamp(int x, int a, int b) { return max(a, min(x, b)); } +//----------------------------------------------------------------------------- +// Settings +//----------------------------------------------------------------------------- + +class SettingsImplWin32 : public Settings { +public: + HKEY hKey = NULL; + + HKEY GetKey() { + if(hKey == NULL) { + sscheck(RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\SolveSpace", 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hKey, NULL)); + } + return hKey; + } + + ~SettingsImplWin32() { + if(hKey != NULL) { + sscheck(RegCloseKey(hKey)); + } + } + + void FreezeInt(const std::string &key, uint32_t value) { + sscheck(RegSetValueExW(GetKey(), &Widen(key)[0], 0, + REG_DWORD, (const BYTE *)&value, sizeof(value))); + } + + uint32_t ThawInt(const std::string &key, uint32_t defaultValue) { + DWORD value; + DWORD type, length = sizeof(value); + LSTATUS result = RegQueryValueEx(GetKey(), &Widen(key)[0], 0, + &type, (BYTE *)&value, &length); + if(result == ERROR_SUCCESS && type == REG_DWORD) { + return value; + } + return defaultValue; + } + + void FreezeFloat(const std::string &key, double value) { + sscheck(RegSetValueExW(GetKey(), &Widen(key)[0], 0, + REG_QWORD, (const BYTE *)&value, sizeof(value))); + } + + double ThawFloat(const std::string &key, double defaultValue) { + double value; + DWORD type, length = sizeof(value); + LSTATUS result = RegQueryValueEx(GetKey(), &Widen(key)[0], 0, + &type, (BYTE *)&value, &length); + if(result == ERROR_SUCCESS && type == REG_QWORD) { + return value; + } + return defaultValue; + } + + void FreezeString(const std::string &key, const std::string &value) { + ssassert(value.length() == strlen(value.c_str()), + "illegal null byte in middle of a string setting"); + std::wstring valueW = Widen(value); + sscheck(RegSetValueExW(GetKey(), &Widen(key)[0], 0, + REG_SZ, (const BYTE *)&valueW[0], (valueW.length() + 1) * 2)); + } + + std::string ThawString(const std::string &key, const std::string &defaultValue) { + DWORD type, length = 0; + LSTATUS result = RegQueryValueEx(GetKey(), &Widen(key)[0], 0, + &type, NULL, &length); + if(result == ERROR_SUCCESS && type == REG_SZ) { + std::wstring valueW; + valueW.resize(length / 2 - 1); + sscheck(RegQueryValueEx(GetKey(), &Widen(key)[0], 0, + &type, (BYTE *)&valueW[0], &length)); + return Narrow(valueW); + } + return defaultValue; + } +}; + +SettingsRef GetSettings() { + return std::make_shared(); +} + //----------------------------------------------------------------------------- // Timers //----------------------------------------------------------------------------- @@ -960,28 +1041,28 @@ public: } } - void FreezePosition(const std::string &key) override { + void FreezePosition(SettingsRef settings, const std::string &key) override { sscheck(GetWindowPlacement(hWindow, &placement)); BOOL isMaximized; sscheck(isMaximized = IsZoomed(hWindow)); RECT rc = placement.rcNormalPosition; - CnfFreezeInt(rc.left, key + "_left"); - CnfFreezeInt(rc.right, key + "_right"); - CnfFreezeInt(rc.top, key + "_top"); - CnfFreezeInt(rc.bottom, key + "_bottom"); - CnfFreezeInt(isMaximized, key + "_maximized"); + settings->FreezeInt(key + "_Left", rc.left); + settings->FreezeInt(key + "_Right", rc.right); + settings->FreezeInt(key + "_Top", rc.top); + settings->FreezeInt(key + "_Bottom", rc.bottom); + settings->FreezeBool(key + "_Maximized", isMaximized); } - void ThawPosition(const std::string &key) override { + void ThawPosition(SettingsRef settings, const std::string &key) override { sscheck(GetWindowPlacement(hWindow, &placement)); RECT rc = placement.rcNormalPosition; - rc.left = CnfThawInt(rc.left, key + "_left"); - rc.right = CnfThawInt(rc.right, key + "_right"); - rc.top = CnfThawInt(rc.top, key + "_top"); - rc.bottom = CnfThawInt(rc.bottom, key + "_bottom"); + rc.left = settings->ThawInt(key + "_Left", rc.left); + rc.right = settings->ThawInt(key + "_Right", rc.right); + rc.top = settings->ThawInt(key + "_Top", rc.top); + rc.bottom = settings->ThawInt(key + "_Bottom", rc.bottom); MONITORINFO mi; mi.cbSize = sizeof(mi); @@ -999,7 +1080,7 @@ public: sscheck(SendMessageW(hWindow, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rc)); placement.flags = 0; - if(CnfThawInt(false, key + "_maximized")) { + if(settings->ThawBool(key + "_Maximized", false)) { placement.showCmd = SW_SHOWMAXIMIZED; } else { placement.showCmd = SW_SHOW; diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index da7058a..b6b9ad6 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -177,102 +177,6 @@ void SolveSpace::OpenWebsite(const char *url) { L"open", Widen(url).c_str(), NULL, NULL, SW_SHOWNORMAL); } -//----------------------------------------------------------------------------- -// Helpers so that we can read/write registry keys from the platform- -// independent code. -//----------------------------------------------------------------------------- - -static HKEY GetRegistryKey() -{ - HKEY Software; - if(RegOpenKeyExW(HKEY_CURRENT_USER, L"Software", 0, - KEY_ALL_ACCESS, &Software) != ERROR_SUCCESS) - return NULL; - - HKEY SolveSpace; - if(RegCreateKeyExW(Software, L"SolveSpace", 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &SolveSpace, NULL) != ERROR_SUCCESS) - return NULL; - - RegCloseKey(Software); - - return SolveSpace; -} - -void SolveSpace::CnfFreezeInt(uint32_t val, const std::string &name) -{ - HKEY SolveSpace = GetRegistryKey(); - RegSetValueExW(SolveSpace, &Widen(name)[0], 0, - REG_DWORD, (const BYTE*) &val, sizeof(DWORD)); - RegCloseKey(SolveSpace); -} -void SolveSpace::CnfFreezeFloat(float val, const std::string &name) -{ - static_assert(sizeof(float) == sizeof(DWORD), - "sizes of float and DWORD must match"); - HKEY SolveSpace = GetRegistryKey(); - RegSetValueExW(SolveSpace, &Widen(name)[0], 0, - REG_DWORD, (const BYTE*) &val, sizeof(DWORD)); - RegCloseKey(SolveSpace); -} -void SolveSpace::CnfFreezeString(const std::string &str, const std::string &name) -{ - HKEY SolveSpace = GetRegistryKey(); - std::wstring strW = Widen(str); - RegSetValueExW(SolveSpace, &Widen(name)[0], 0, - REG_SZ, (const BYTE*) &strW[0], (strW.length() + 1) * 2); - RegCloseKey(SolveSpace); -} - -uint32_t SolveSpace::CnfThawInt(uint32_t val, const std::string &name) -{ - HKEY SolveSpace = GetRegistryKey(); - DWORD type, newval, len = sizeof(DWORD); - LONG result = RegQueryValueEx(SolveSpace, &Widen(name)[0], NULL, - &type, (BYTE*) &newval, &len); - RegCloseKey(SolveSpace); - - if(result == ERROR_SUCCESS && type == REG_DWORD) - return newval; - else - return val; -} -float SolveSpace::CnfThawFloat(float val, const std::string &name) -{ - HKEY SolveSpace = GetRegistryKey(); - DWORD type, len = sizeof(DWORD); - float newval; - LONG result = RegQueryValueExW(SolveSpace, &Widen(name)[0], NULL, - &type, (BYTE*) &newval, &len); - RegCloseKey(SolveSpace); - - if(result == ERROR_SUCCESS && type == REG_DWORD) - return newval; - else - return val; -} -std::string SolveSpace::CnfThawString(const std::string &val, const std::string &name) -{ - HKEY SolveSpace = GetRegistryKey(); - DWORD type, len; - if(RegQueryValueExW(SolveSpace, &Widen(name)[0], NULL, - &type, NULL, &len) != ERROR_SUCCESS || type != REG_SZ) { - RegCloseKey(SolveSpace); - return val; - } - - std::wstring newval; - newval.resize(len / 2 - 1); - if(RegQueryValueExW(SolveSpace, &Widen(name)[0], NULL, - NULL, (BYTE*) &newval[0], &len) != ERROR_SUCCESS) { - RegCloseKey(SolveSpace); - return val; - } - - RegCloseKey(SolveSpace); - return Narrow(newval); -} - //----------------------------------------------------------------------------- // Common dialog routines, to open or save a file. //----------------------------------------------------------------------------- diff --git a/src/sketch.h b/src/sketch.h index 1b88a08..7bf49ff 100644 --- a/src/sketch.h +++ b/src/sketch.h @@ -834,7 +834,7 @@ public: static void CreateAllDefaultStyles(); static void CreateDefaultStyle(hStyle h); static void FillDefaultStyle(Style *s, const Default *d = NULL, bool factory = false); - static void FreezeDefaultStyles(); + static void FreezeDefaultStyles(Platform::SettingsRef settings); static void LoadFactoryDefaults(); static void AssignSelectionToStyle(uint32_t v); diff --git a/src/solvespace.cpp b/src/solvespace.cpp index e36a32e..1884075 100644 --- a/src/solvespace.cpp +++ b/src/solvespace.cpp @@ -16,95 +16,97 @@ void SolveSpaceUI::Init() { dbp("%s", LoadString("banner.txt").data()); #endif + Platform::SettingsRef settings = Platform::GetSettings(); + SS.tangentArcRadius = 10.0; // Then, load the registry settings. // Default list of colors for the model material - modelColor[0] = CnfThawColor(RGBi(150, 150, 150), "ModelColor_0"); - modelColor[1] = CnfThawColor(RGBi(100, 100, 100), "ModelColor_1"); - modelColor[2] = CnfThawColor(RGBi( 30, 30, 30), "ModelColor_2"); - modelColor[3] = CnfThawColor(RGBi(150, 0, 0), "ModelColor_3"); - modelColor[4] = CnfThawColor(RGBi( 0, 100, 0), "ModelColor_4"); - modelColor[5] = CnfThawColor(RGBi( 0, 80, 80), "ModelColor_5"); - modelColor[6] = CnfThawColor(RGBi( 0, 0, 130), "ModelColor_6"); - modelColor[7] = CnfThawColor(RGBi( 80, 0, 80), "ModelColor_7"); + modelColor[0] = settings->ThawColor("ModelColor_0", RGBi(150, 150, 150)); + modelColor[1] = settings->ThawColor("ModelColor_1", RGBi(100, 100, 100)); + modelColor[2] = settings->ThawColor("ModelColor_2", RGBi( 30, 30, 30)); + modelColor[3] = settings->ThawColor("ModelColor_3", RGBi(150, 0, 0)); + modelColor[4] = settings->ThawColor("ModelColor_4", RGBi( 0, 100, 0)); + modelColor[5] = settings->ThawColor("ModelColor_5", RGBi( 0, 80, 80)); + modelColor[6] = settings->ThawColor("ModelColor_6", RGBi( 0, 0, 130)); + modelColor[7] = settings->ThawColor("ModelColor_7", RGBi( 80, 0, 80)); // Light intensities - lightIntensity[0] = CnfThawFloat(1.0f, "LightIntensity_0"); - lightIntensity[1] = CnfThawFloat(0.5f, "LightIntensity_1"); + lightIntensity[0] = settings->ThawFloat("LightIntensity_0", 1.0f); + lightIntensity[1] = settings->ThawFloat("LightIntensity_1", 0.5f); ambientIntensity = 0.3; // no setting for that yet // Light positions - lightDir[0].x = CnfThawFloat(-1.0f, "LightDir_0_Right" ); - lightDir[0].y = CnfThawFloat( 1.0f, "LightDir_0_Up" ); - lightDir[0].z = CnfThawFloat( 0.0f, "LightDir_0_Forward" ); - lightDir[1].x = CnfThawFloat( 1.0f, "LightDir_1_Right" ); - lightDir[1].y = CnfThawFloat( 0.0f, "LightDir_1_Up" ); - lightDir[1].z = CnfThawFloat( 0.0f, "LightDir_1_Forward" ); + lightDir[0].x = settings->ThawFloat("LightDir_0_Right", -1.0f); + lightDir[0].y = settings->ThawFloat("LightDir_0_Up", 1.0f); + lightDir[0].z = settings->ThawFloat("LightDir_0_Forward", 0.0f); + lightDir[1].x = settings->ThawFloat("LightDir_1_Right", 1.0f); + lightDir[1].y = settings->ThawFloat("LightDir_1_Up", 0.0f); + lightDir[1].z = settings->ThawFloat("LightDir_1_Forward", 0.0f); exportMode = false; // Chord tolerance - chordTol = CnfThawFloat(0.5f, "ChordTolerancePct"); + chordTol = settings->ThawFloat("ChordTolerancePct", 0.5f); // Max pwl segments to generate - maxSegments = CnfThawInt(10, "MaxSegments"); + maxSegments = settings->ThawInt("MaxSegments", 10); // Chord tolerance - exportChordTol = CnfThawFloat(0.1f, "ExportChordTolerance"); + exportChordTol = settings->ThawFloat("ExportChordTolerance", 0.1f); // Max pwl segments to generate - exportMaxSegments = CnfThawInt(64, "ExportMaxSegments"); + exportMaxSegments = settings->ThawInt("ExportMaxSegments", 64); // View units - viewUnits = (Unit)CnfThawInt((uint32_t)Unit::MM, "ViewUnits"); + viewUnits = (Unit)settings->ThawInt("ViewUnits", (uint32_t)Unit::MM); // Number of digits after the decimal point - afterDecimalMm = CnfThawInt(2, "AfterDecimalMm"); - afterDecimalInch = CnfThawInt(3, "AfterDecimalInch"); + afterDecimalMm = settings->ThawInt("AfterDecimalMm", 2); + afterDecimalInch = settings->ThawInt("AfterDecimalInch", 3); // Camera tangent (determines perspective) - cameraTangent = CnfThawFloat(0.3f/1e3f, "CameraTangent"); + cameraTangent = settings->ThawFloat("CameraTangent", 0.3f/1e3f); // Grid spacing - gridSpacing = CnfThawFloat(5.0f, "GridSpacing"); + gridSpacing = settings->ThawFloat("GridSpacing", 5.0f); // Export scale factor - exportScale = CnfThawFloat(1.0f, "ExportScale"); + exportScale = settings->ThawFloat("ExportScale", 1.0f); // Export offset (cutter radius comp) - exportOffset = CnfThawFloat(0.0f, "ExportOffset"); + exportOffset = settings->ThawFloat("ExportOffset", 0.0f); // Rewrite exported colors close to white into black (assuming white bg) - fixExportColors = CnfThawBool(true, "FixExportColors"); + fixExportColors = settings->ThawBool("FixExportColors", true); // Draw back faces of triangles (when mesh is leaky/self-intersecting) - drawBackFaces = CnfThawBool(true, "DrawBackFaces"); + drawBackFaces = settings->ThawBool("DrawBackFaces", true); // Check that contours are closed and not self-intersecting - checkClosedContour = CnfThawBool(true, "CheckClosedContour"); + checkClosedContour = settings->ThawBool("CheckClosedContour", true); // Draw closed polygons areas - showContourAreas = CnfThawBool(false, "ShowContourAreas"); + showContourAreas = settings->ThawBool("ShowContourAreas", false); // Export shaded triangles in a 2d view - exportShadedTriangles = CnfThawBool(true, "ExportShadedTriangles"); + exportShadedTriangles = settings->ThawBool("ExportShadedTriangles", true); // Export pwl curves (instead of exact) always - exportPwlCurves = CnfThawBool(false, "ExportPwlCurves"); + exportPwlCurves = settings->ThawBool("ExportPwlCurves", false); // Background color on-screen - backgroundColor = CnfThawColor(RGBi(0, 0, 0), "BackgroundColor"); + backgroundColor = settings->ThawColor("BackgroundColor", RGBi(0, 0, 0)); // Whether export canvas size is fixed or derived from bbox - exportCanvasSizeAuto = CnfThawBool(true, "ExportCanvasSizeAuto"); + exportCanvasSizeAuto = settings->ThawBool("ExportCanvasSizeAuto", true); // Margins for automatic canvas size - exportMargin.left = CnfThawFloat(5.0f, "ExportMargin_Left"); - exportMargin.right = CnfThawFloat(5.0f, "ExportMargin_Right"); - exportMargin.bottom = CnfThawFloat(5.0f, "ExportMargin_Bottom"); - exportMargin.top = CnfThawFloat(5.0f, "ExportMargin_Top"); + exportMargin.left = settings->ThawFloat("ExportMargin_Left", 5.0f); + exportMargin.right = settings->ThawFloat("ExportMargin_Right", 5.0f); + exportMargin.bottom = settings->ThawFloat("ExportMargin_Bottom", 5.0f); + exportMargin.top = settings->ThawFloat("ExportMargin_Top", 5.0f); // Dimensions for fixed canvas size - exportCanvas.width = CnfThawFloat(100.0f, "ExportCanvas_Width"); - exportCanvas.height = CnfThawFloat(100.0f, "ExportCanvas_Height"); - exportCanvas.dx = CnfThawFloat( 5.0f, "ExportCanvas_Dx"); - exportCanvas.dy = CnfThawFloat( 5.0f, "ExportCanvas_Dy"); + exportCanvas.width = settings->ThawFloat("ExportCanvas_Width", 100.0f); + exportCanvas.height = settings->ThawFloat("ExportCanvas_Height", 100.0f); + exportCanvas.dx = settings->ThawFloat("ExportCanvas_Dx", 5.0f); + exportCanvas.dy = settings->ThawFloat("ExportCanvas_Dy", 5.0f); // Extra parameters when exporting G code - gCode.depth = CnfThawFloat(10.0f, "GCode_Depth"); - gCode.passes = CnfThawInt(1, "GCode_Passes"); - gCode.feed = CnfThawFloat(10.0f, "GCode_Feed"); - gCode.plungeFeed = CnfThawFloat(10.0f, "GCode_PlungeFeed"); + gCode.depth = settings->ThawFloat("GCode_Depth", 10.0f); + gCode.passes = settings->ThawInt("GCode_Passes", 1); + gCode.feed = settings->ThawFloat("GCode_Feed", 10.0f); + gCode.plungeFeed = settings->ThawFloat("GCode_PlungeFeed", 10.0f); // Show toolbar in the graphics window - showToolbar = CnfThawBool(true, "ShowToolbar"); + showToolbar = settings->ThawBool("ShowToolbar", true); // Recent files menus for(size_t i = 0; i < MAX_RECENT; i++) { - std::string rawPath = CnfThawString("", "RecentFile_" + std::to_string(i)); + std::string rawPath = settings->ThawString("RecentFile_" + std::to_string(i), ""); if(rawPath.empty()) continue; recentFiles.push_back(Platform::Path::From(rawPath)); } // Autosave timer - autosaveInterval = CnfThawInt(5, "AutosaveInterval"); + autosaveInterval = settings->ThawInt("AutosaveInterval", 5); // Locale - std::string locale = CnfThawString("", "Locale"); + std::string locale = settings->ThawString("Locale", ""); if(!locale.empty()) { SetLocale(locale); } @@ -129,9 +131,9 @@ void SolveSpaceUI::Init() { AfterNewFile(); if(TW.window && GW.window) { - TW.window->ThawPosition("TextWindow"); + TW.window->ThawPosition(settings, "TextWindow"); + GW.window->ThawPosition(settings, "GraphicsWindow"); TW.window->SetVisible(true); - GW.window->ThawPosition("GraphicsWindow"); GW.window->SetVisible(true); GW.window->Focus(); } @@ -169,8 +171,10 @@ bool SolveSpaceUI::Load(const Platform::Path &filename) { } void SolveSpaceUI::Exit() { - GW.window->FreezePosition("GraphicsWindow"); - TW.window->FreezePosition("TextWindow"); + Platform::SettingsRef settings = Platform::GetSettings(); + + GW.window->FreezePosition(settings, "GraphicsWindow"); + TW.window->FreezePosition(settings, "TextWindow"); // Recent files for(size_t i = 0; i < MAX_RECENT; i++) { @@ -178,80 +182,80 @@ void SolveSpaceUI::Exit() { if(recentFiles.size() > i) { rawPath = recentFiles[i].raw; } - CnfFreezeString(rawPath, "RecentFile_" + std::to_string(i)); + settings->FreezeString("RecentFile_" + std::to_string(i), rawPath); } // Model colors for(size_t i = 0; i < MODEL_COLORS; i++) - CnfFreezeColor(modelColor[i], "ModelColor_" + std::to_string(i)); + settings->FreezeColor("ModelColor_" + std::to_string(i), modelColor[i]); // Light intensities - CnfFreezeFloat((float)lightIntensity[0], "LightIntensity_0"); - CnfFreezeFloat((float)lightIntensity[1], "LightIntensity_1"); + settings->FreezeFloat("LightIntensity_0", (float)lightIntensity[0]); + settings->FreezeFloat("LightIntensity_1", (float)lightIntensity[1]); // Light directions - CnfFreezeFloat((float)lightDir[0].x, "LightDir_0_Right"); - CnfFreezeFloat((float)lightDir[0].y, "LightDir_0_Up"); - CnfFreezeFloat((float)lightDir[0].z, "LightDir_0_Forward"); - CnfFreezeFloat((float)lightDir[1].x, "LightDir_1_Right"); - CnfFreezeFloat((float)lightDir[1].y, "LightDir_1_Up"); - CnfFreezeFloat((float)lightDir[1].z, "LightDir_1_Forward"); + settings->FreezeFloat("LightDir_0_Right", (float)lightDir[0].x); + settings->FreezeFloat("LightDir_0_Up", (float)lightDir[0].y); + settings->FreezeFloat("LightDir_0_Forward", (float)lightDir[0].z); + settings->FreezeFloat("LightDir_1_Right", (float)lightDir[1].x); + settings->FreezeFloat("LightDir_1_Up", (float)lightDir[1].y); + settings->FreezeFloat("LightDir_1_Forward", (float)lightDir[1].z); // Chord tolerance - CnfFreezeFloat((float)chordTol, "ChordTolerancePct"); + settings->FreezeFloat("ChordTolerancePct", (float)chordTol); // Max pwl segments to generate - CnfFreezeInt((uint32_t)maxSegments, "MaxSegments"); + settings->FreezeInt("MaxSegments", (uint32_t)maxSegments); // Export Chord tolerance - CnfFreezeFloat((float)exportChordTol, "ExportChordTolerance"); + settings->FreezeFloat("ExportChordTolerance", (float)exportChordTol); // Export Max pwl segments to generate - CnfFreezeInt((uint32_t)exportMaxSegments, "ExportMaxSegments"); + settings->FreezeInt("ExportMaxSegments", (uint32_t)exportMaxSegments); // View units - CnfFreezeInt((uint32_t)viewUnits, "ViewUnits"); + settings->FreezeInt("ViewUnits", (uint32_t)viewUnits); // Number of digits after the decimal point - CnfFreezeInt((uint32_t)afterDecimalMm, "AfterDecimalMm"); - CnfFreezeInt((uint32_t)afterDecimalInch, "AfterDecimalInch"); + settings->FreezeInt("AfterDecimalMm", (uint32_t)afterDecimalMm); + settings->FreezeInt("AfterDecimalInch", (uint32_t)afterDecimalInch); // Camera tangent (determines perspective) - CnfFreezeFloat((float)cameraTangent, "CameraTangent"); + settings->FreezeFloat("CameraTangent", (float)cameraTangent); // Grid spacing - CnfFreezeFloat(gridSpacing, "GridSpacing"); + settings->FreezeFloat("GridSpacing", gridSpacing); // Export scale - CnfFreezeFloat(exportScale, "ExportScale"); + settings->FreezeFloat("ExportScale", exportScale); // Export offset (cutter radius comp) - CnfFreezeFloat(exportOffset, "ExportOffset"); + settings->FreezeFloat("ExportOffset", exportOffset); // Rewrite exported colors close to white into black (assuming white bg) - CnfFreezeBool(fixExportColors, "FixExportColors"); + settings->FreezeBool("FixExportColors", fixExportColors); // Draw back faces of triangles (when mesh is leaky/self-intersecting) - CnfFreezeBool(drawBackFaces, "DrawBackFaces"); + settings->FreezeBool("DrawBackFaces", drawBackFaces); // Draw closed polygons areas - CnfFreezeBool(showContourAreas, "ShowContourAreas"); + settings->FreezeBool("ShowContourAreas", showContourAreas); // Check that contours are closed and not self-intersecting - CnfFreezeBool(checkClosedContour, "CheckClosedContour"); + settings->FreezeBool("CheckClosedContour", checkClosedContour); // Export shaded triangles in a 2d view - CnfFreezeBool(exportShadedTriangles, "ExportShadedTriangles"); + settings->FreezeBool("ExportShadedTriangles", exportShadedTriangles); // Export pwl curves (instead of exact) always - CnfFreezeBool(exportPwlCurves, "ExportPwlCurves"); + settings->FreezeBool("ExportPwlCurves", exportPwlCurves); // Background color on-screen - CnfFreezeColor(backgroundColor, "BackgroundColor"); + settings->FreezeColor("BackgroundColor", backgroundColor); // Whether export canvas size is fixed or derived from bbox - CnfFreezeBool(exportCanvasSizeAuto, "ExportCanvasSizeAuto"); + settings->FreezeBool("ExportCanvasSizeAuto", exportCanvasSizeAuto); // Margins for automatic canvas size - CnfFreezeFloat(exportMargin.left, "ExportMargin_Left"); - CnfFreezeFloat(exportMargin.right, "ExportMargin_Right"); - CnfFreezeFloat(exportMargin.bottom, "ExportMargin_Bottom"); - CnfFreezeFloat(exportMargin.top, "ExportMargin_Top"); + settings->FreezeFloat("ExportMargin_Left", exportMargin.left); + settings->FreezeFloat("ExportMargin_Right", exportMargin.right); + settings->FreezeFloat("ExportMargin_Bottom", exportMargin.bottom); + settings->FreezeFloat("ExportMargin_Top", exportMargin.top); // Dimensions for fixed canvas size - CnfFreezeFloat(exportCanvas.width, "ExportCanvas_Width"); - CnfFreezeFloat(exportCanvas.height, "ExportCanvas_Height"); - CnfFreezeFloat(exportCanvas.dx, "ExportCanvas_Dx"); - CnfFreezeFloat(exportCanvas.dy, "ExportCanvas_Dy"); + settings->FreezeFloat("ExportCanvas_Width", exportCanvas.width); + settings->FreezeFloat("ExportCanvas_Height", exportCanvas.height); + settings->FreezeFloat("ExportCanvas_Dx", exportCanvas.dx); + settings->FreezeFloat("ExportCanvas_Dy", exportCanvas.dy); // Extra parameters when exporting G code - CnfFreezeFloat(gCode.depth, "GCode_Depth"); - CnfFreezeInt(gCode.passes, "GCode_Passes"); - CnfFreezeFloat(gCode.feed, "GCode_Feed"); - CnfFreezeFloat(gCode.plungeFeed, "GCode_PlungeFeed"); + settings->FreezeFloat("GCode_Depth", gCode.depth); + settings->FreezeInt("GCode_Passes", gCode.passes); + settings->FreezeFloat("GCode_Feed", gCode.feed); + settings->FreezeFloat("GCode_PlungeFeed", gCode.plungeFeed); // Show toolbar in the graphics window - CnfFreezeBool(showToolbar, "ShowToolbar"); + settings->FreezeBool("ShowToolbar", showToolbar); // Autosave timer - CnfFreezeInt(autosaveInterval, "AutosaveInterval"); + settings->FreezeInt("AutosaveInterval", autosaveInterval); // And the default styles, colors and line widths and such. - Style::FreezeDefaultStyles(); + Style::FreezeDefaultStyles(settings); Platform::Exit(); } @@ -444,6 +448,8 @@ void SolveSpaceUI::UpdateWindowTitles() { } void SolveSpaceUI::MenuFile(Command id) { + Platform::SettingsRef settings = Platform::GetSettings(); + switch(id) { case Command::NEW: if(!SS.OkayToStartNewFile()) break; @@ -480,9 +486,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::EXPORT_VIEW: { Platform::Path exportFile = SS.saveFile; - if(!GetSaveFile(&exportFile, CnfThawString("", "ViewExportFormat"), + if(!GetSaveFile(&exportFile, + Platform::GetSettings()->ThawString("ViewExportFormat"), VectorFileFilter)) break; - CnfFreezeString(exportFile.Extension(), "ViewExportFormat"); + settings->FreezeString("ViewExportFormat", exportFile.Extension()); // If the user is exporting something where it would be // inappropriate to include the constraints, then warn. @@ -502,9 +509,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::EXPORT_WIREFRAME: { Platform::Path exportFile = SS.saveFile; - if(!GetSaveFile(&exportFile, CnfThawString("", "WireframeExportFormat"), + if(!GetSaveFile(&exportFile, + Platform::GetSettings()->ThawString("WireframeExportFormat"), Vector3dFileFilter)) break; - CnfFreezeString(exportFile.Extension(), "WireframeExportFormat"); + settings->FreezeString("WireframeExportFormat", exportFile.Extension()); SS.ExportViewOrWireframeTo(exportFile, /*exportWireframe*/true); break; @@ -512,9 +520,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::EXPORT_SECTION: { Platform::Path exportFile = SS.saveFile; - if(!GetSaveFile(&exportFile, CnfThawString("", "SectionExportFormat"), + if(!GetSaveFile(&exportFile, + Platform::GetSettings()->ThawString("SectionExportFormat"), VectorFileFilter)) break; - CnfFreezeString(exportFile.Extension(), "SectionExportFormat"); + settings->FreezeString("SectionExportFormat", exportFile.Extension()); SS.ExportSectionTo(exportFile); break; @@ -522,9 +531,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::EXPORT_MESH: { Platform::Path exportFile = SS.saveFile; - if(!GetSaveFile(&exportFile, CnfThawString("", "MeshExportFormat"), + if(!GetSaveFile(&exportFile, + Platform::GetSettings()->ThawString("MeshExportFormat"), MeshFileFilter)) break; - CnfFreezeString(exportFile.Extension(), "MeshExportFormat"); + settings->FreezeString("MeshExportFormat", exportFile.Extension()); SS.ExportMeshTo(exportFile); break; @@ -532,9 +542,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::EXPORT_SURFACES: { Platform::Path exportFile = SS.saveFile; - if(!GetSaveFile(&exportFile, CnfThawString("", "SurfacesExportFormat"), + if(!GetSaveFile(&exportFile, + Platform::GetSettings()->ThawString("SurfacesExportFormat"), SurfaceFileFilter)) break; - CnfFreezeString(exportFile.Extension(), "SurfacesExportFormat"); + settings->FreezeString("SurfacesExportFormat", exportFile.Extension()); StepFileWriter sfw = {}; sfw.ExportSurfacesTo(exportFile); @@ -543,9 +554,10 @@ void SolveSpaceUI::MenuFile(Command id) { case Command::IMPORT: { Platform::Path importFile; - if(!GetOpenFile(&importFile, CnfThawString("", "ImportFormat"), + if(!GetOpenFile(&importFile, + Platform::GetSettings()->ThawString("ImportFormat"), ImportableFileFilter)) break; - CnfFreezeString(importFile.Extension(), "ImportFormat"); + settings->FreezeString("ImportFormat", importFile.Extension()); if(importFile.HasExtension("dxf")) { ImportDxf(importFile); diff --git a/src/solvespace.h b/src/solvespace.h index 7eb4433..66f3366 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -173,13 +173,6 @@ void dbp(const char *str, ...); void SetMousePointerToHand(bool yes); void DoMessageBox(const char *str, int rows, int cols, bool error); -void CnfFreezeInt(uint32_t val, const std::string &name); -void CnfFreezeFloat(float val, const std::string &name); -void CnfFreezeString(const std::string &val, const std::string &name); -std::string CnfThawString(const std::string &val, const std::string &name); -uint32_t CnfThawInt(uint32_t val, const std::string &name); -float CnfThawFloat(float val, const std::string &name); - std::vector InitPlatform(int argc, char **argv); void *AllocTemporary(size_t n); @@ -263,10 +256,6 @@ void MultMatrix(double *mata, double *matb, double *matr); int64_t GetMilliseconds(); void Message(const char *str, ...); void Error(const char *str, ...); -void CnfFreezeBool(bool v, const std::string &name); -void CnfFreezeColor(RgbaColor v, const std::string &name); -bool CnfThawBool(bool v, const std::string &name); -RgbaColor CnfThawColor(RgbaColor v, const std::string &name); class System { public: diff --git a/src/style.cpp b/src/style.cpp index 78090c5..c3fcff5 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -81,12 +81,18 @@ void Style::CreateDefaultStyle(hStyle h) { } void Style::FillDefaultStyle(Style *s, const Default *d, bool factory) { + Platform::SettingsRef settings = Platform::GetSettings(); + if(d == NULL) d = &Defaults[0]; - s->color = (factory) ? d->color : CnfThawColor(d->color, CnfColor(d->cnfPrefix)); - s->width = (factory) ? d->width : CnfThawFloat((float)(d->width), CnfWidth(d->cnfPrefix)); + s->color = (factory) + ? d->color + : settings->ThawColor(CnfColor(d->cnfPrefix), d->color); + s->width = (factory) + ? d->width + : settings->ThawFloat(CnfWidth(d->cnfPrefix), (float)(d->width)); s->widthAs = UnitsAs::PIXELS; s->textHeight = (factory) ? 11.5 - : CnfThawFloat(11.5, CnfTextHeight(d->cnfPrefix)); + : settings->ThawFloat(CnfTextHeight(d->cnfPrefix), 11.5); s->textHeightAs = UnitsAs::PIXELS; s->textOrigin = TextOrigin::NONE; s->textAngle = 0; @@ -109,12 +115,12 @@ void Style::LoadFactoryDefaults() { SS.backgroundColor = RGBi(0, 0, 0); } -void Style::FreezeDefaultStyles() { +void Style::FreezeDefaultStyles(Platform::SettingsRef settings) { const Default *d; for(d = &(Defaults[0]); d->h.v; d++) { - CnfFreezeColor(Color(d->h), CnfColor(d->cnfPrefix)); - CnfFreezeFloat((float)Width(d->h), CnfWidth(d->cnfPrefix)); - CnfFreezeFloat((float)TextHeight(d->h), CnfTextHeight(d->cnfPrefix)); + settings->FreezeColor(CnfColor(d->cnfPrefix), Color(d->h)); + settings->FreezeFloat(CnfWidth(d->cnfPrefix), (float)Width(d->h)); + settings->FreezeFloat(CnfTextHeight(d->cnfPrefix), (float)TextHeight(d->h)); } } diff --git a/src/util.cpp b/src/util.cpp index 658b9ce..f4064f5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -173,18 +173,6 @@ void SolveSpace::Message(const char *str, ...) va_end(f); } -void SolveSpace::CnfFreezeBool(bool v, const std::string &name) - { CnfFreezeInt(v ? 1 : 0, name); } - -void SolveSpace::CnfFreezeColor(RgbaColor v, const std::string &name) - { CnfFreezeInt(v.ToPackedInt(), name); } - -bool SolveSpace::CnfThawBool(bool v, const std::string &name) - { return CnfThawInt(v ? 1 : 0, name) != 0; } - -RgbaColor SolveSpace::CnfThawColor(RgbaColor v, const std::string &name) - { return RgbaColor::FromPackedInt(CnfThawInt(v.ToPackedInt(), name)); } - //----------------------------------------------------------------------------- // Solve a mostly banded matrix. In a given row, there are LEFT_OF_DIAG // elements to the left of the diagonal element, and RIGHT_OF_DIAG elements to