From 65c70fa9be2753222eb553d92eb63e84106cd744 Mon Sep 17 00:00:00 2001 From: LiveLM Date: Fri, 7 Apr 2023 14:59:30 -0300 Subject: [PATCH] Implement Settings (#12) * Add settings class * Serialize settings to XML when settings window is closed * Rename Settings class to Config * Create functions for loading, saving and creating the default config * Use the new functions to write ConfigXML to disk when settings window is closed * Load config on startup + move default config from constructor to function * Move Config out of XML Folder * Implement saving and restoring field info * Fix unnecessary object creation and XML Attribute names * Save "SystemLanguage" option to config properly * Load text dynamically + Choose proper language when "SystemLanguage" is selected * Restore SystemLanguage setting properly + Make System Language the default * Fix typo in English locale * Change XmlRoot attributes to more descriptive ones * Move Config saving when closing application to a separate method * Move Config saving when closing Settings window to separate method * Use path.combine properly * Make LoadAndReturnConfig more concise * Reset to SystemLanguage if trying to load a invalid language * Enable Fill in fields by default * Add documentation to Config.cs and FieldContents.cs --- Atomic/Language/Text.resx | 4 +- Atomic/ModPacker.Designer.cs | 120 ++++++++++++++++++++++++++--------- Atomic/ModPacker.cs | 20 ++++++ Atomic/SettingsForm.cs | 34 ++++++---- AtomicLib/Config.cs | 81 +++++++++++++++++++++++ AtomicLib/FieldContents.cs | 68 ++++++++++++++++++++ 6 files changed, 284 insertions(+), 43 deletions(-) create mode 100644 AtomicLib/Config.cs create mode 100644 AtomicLib/FieldContents.cs diff --git a/Atomic/Language/Text.resx b/Atomic/Language/Text.resx index 031e4fb..a83679b 100644 --- a/Atomic/Language/Text.resx +++ b/Atomic/Language/Text.resx @@ -142,7 +142,7 @@ System Language - Language (change requires a retart) + Language (change requires a restart) Settings @@ -159,4 +159,4 @@ &File - \ No newline at end of file + diff --git a/Atomic/ModPacker.Designer.cs b/Atomic/ModPacker.Designer.cs index 039a5a4..960cb7b 100644 --- a/Atomic/ModPacker.Designer.cs +++ b/Atomic/ModPacker.Designer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Eto.Forms; using Eto.Drawing; @@ -5,8 +6,11 @@ using AtomicLib.XML; using System.IO; using System.Net.Mime; using System.Reflection; +using System.Threading; using AtomicLib; using Atomic.Language; +using System.Globalization; +using System.Linq; namespace Atomic; @@ -56,7 +60,46 @@ public partial class ModPacker : Form // loop through all resource files for test //ResXResourceReader rsxr = new ResXResourceReader("items.resx"); + currentConfig = Config.LoadAndReturnConfig(); + if (!currentConfig.Language.Equals("SystemLanguage")) + { + CultureInfo language = CultureInfo.GetCultures(CultureTypes.AllCultures).FirstOrDefault(c => c.NativeName.ToLower().Contains(currentConfig.Language.ToLower())); + if (language is null) currentConfig.Language = "SystemLanguage"; + else Thread.CurrentThread.CurrentUICulture = language; + } + + nameLabel.Text = Text.ModName; + authorLabel.Text = Text.Author; + versionLabel.Text = Text.Version; + modNotesLabel.Text = Text.ModNotes; + + customSaveCheckBox.Text = Text.UsesCustomSaves; + customSaveButton.Text = Text.SelectFolder; + musicCheckBox.Text = Text.UsesCustomMusic; + + yycCheckBox.Text = Text.UsesYYC; + + windowsCheckBox.Text = Text.SupportsOS.Replace("$1", Text.Windows); + windowsButton.Text = Text.LoadOSZip.Replace("$1", Text.Windows); + windowsLabel.Text = Text.OSGameLoaded.Replace("$1", Text.Windows); + + apkCheckBox.Text = Text.BundleAndroid; + apkButton.Text = Text.LoadAndroidAPK; + apkLabel.Text = Text.AndroidLoaded; + + linuxCheckBox.Text = Text.SupportsOS.Replace("$1", Text.Linux); + linuxButton.Text = Text.LoadOSZip.Replace("$1", Text.Linux); + linuxLabel.Text = Text.OSGameLoaded.Replace("$1", Text.Linux); + + macCheckBox.Text = Text.SupportsOS.Replace("$1", Text.Mac); + macButton.Text = Text.LoadOSZip.Replace("$1", Text.Mac); + macLabel.Text = Text.OSGameLoaded.Replace("$1", Text.Mac); + + originalZipButton.Text = Text.LoadAM2R11; + originalZipLabel.Text = Text.AM2R11Loaded; + createButton.Text = Text.CreateModPackage; + createLabel.Text = Text.ModPackageCreated; Title = "Atomic v" + version; Icon = new Icon(1f, new Bitmap(Resources.icon64)); @@ -144,12 +187,29 @@ public partial class ModPacker : Form customSaveCheckBox.CheckedChanged += CustomSaveCheckBoxChecked_Changed; customSaveButton.Click += CustomSaveDataButton_Click; yycCheckBox.CheckedChanged += YYCCheckBox_CheckedChanged; + this.Closing += ModPacker_Closing; + + if (currentConfig.FillInContents && currentConfig.Fields != null) + { + nameTextBox.Text = currentConfig.Fields.ModName; + authorTextBox.Text = currentConfig.Fields.Author; + versionTextBox.Text = currentConfig.Fields.Version; + modNotesTextBox.Text = currentConfig.Fields.Notes; + customSaveCheckBox.Checked = currentConfig.Fields.UsesCustomSave; + customSaveTextBox.Text = currentConfig.Fields.CustomSaveDir; + musicCheckBox.Checked = currentConfig.Fields.UsesCustomMusic; + yycCheckBox.Checked = currentConfig.Fields.UsesYYC; + windowsCheckBox.Checked = currentConfig.Fields.SupportsWindows; + linuxCheckBox.Checked = currentConfig.Fields.SupportsLinux; + macCheckBox.Checked = currentConfig.Fields.SupportsMac; + apkCheckBox.Checked = currentConfig.Fields.SupportsAndroid; + } // Menu items var settings = new Command() { MenuText = Text.SettingsMenu, Shortcut = Application.Instance.CommonModifier | Application.Instance.AlternateModifier | Keys.P}; settings.Executed += (sender, args) => { - var settings = new SettingsForm(); + var settings = new SettingsForm(currentConfig); settings.ShowModal(); }; var quit = new Command() { MenuText = Text.QuitMenu, Shortcut = Application.Instance.CommonModifier | Keys.Q}; @@ -159,43 +219,45 @@ public partial class ModPacker : Form Menu = new MenuBar() {Items = { file }}; } + private Config currentConfig; + #region Design Elements - private Label nameLabel = new Label() { Text = Text.ModName }; + private Label nameLabel = new Label(); private TextBox nameTextBox = new TextBox(); - private Label authorLabel = new Label() { Text = Text.Author }; + private Label authorLabel = new Label(); private TextBox authorTextBox = new TextBox(); - private Label versionLabel = new Label() { Text = Text.Version }; + private Label versionLabel = new Label(); private TextBox versionTextBox = new TextBox(); - private Label modNotesLabel = new Label() { Text = Text.ModNotes }; - private TextArea modNotesTextBox = new TextArea() { }; + private Label modNotesLabel = new Label(); + private TextArea modNotesTextBox = new TextArea(); - private CheckBox customSaveCheckBox = new CheckBox() { Text = Text.UsesCustomSaves }; - private Button customSaveButton = new Button() { Text = Text.SelectFolder, Enabled = false }; + private CheckBox customSaveCheckBox = new CheckBox(); + private Button customSaveButton = new Button() { Enabled = false }; // TODO: remove read only and make it correctly respond to user input private TextBox customSaveTextBox = new TextBox() { ReadOnly = true }; - private CheckBox musicCheckBox = new CheckBox() { Text = Text.UsesCustomMusic }; + private CheckBox musicCheckBox = new CheckBox(); + + private CheckBox yycCheckBox = new CheckBox(); - private CheckBox yycCheckBox = new CheckBox() { Text = Text.UsesYYC }; + private CheckBox windowsCheckBox = new CheckBox(); + private Button windowsButton = new Button() { Enabled = false }; + private Label windowsLabel = new Label() { Visible = false }; - private CheckBox windowsCheckBox = new CheckBox() { Text = Text.SupportsOS.Replace("$1", Text.Windows) }; - private Button windowsButton = new Button() { Text = Text.LoadOSZip.Replace("$1", Text.Windows), Enabled = false }; - private Label windowsLabel = new Label() { Text = Text.OSGameLoaded.Replace("$1", Text.Windows), Visible = false }; - - private CheckBox apkCheckBox = new CheckBox() { Text = Text.BundleAndroid }; - private Button apkButton = new Button() { Text = Text.LoadAndroidAPK, Enabled = false }; - private Label apkLabel = new Label() { Text = Text.AndroidLoaded, Visible = false }; + private CheckBox apkCheckBox = new CheckBox(); + private Button apkButton = new Button() { Enabled = false }; + private Label apkLabel = new Label() { Visible = false }; - private CheckBox linuxCheckBox = new CheckBox() { Text = Text.SupportsOS.Replace("$1", Text.Linux)}; - private Button linuxButton = new Button() { Text = Text.LoadOSZip.Replace("$1", Text.Linux), Enabled = false }; - private Label linuxLabel = new Label() { Text = Text.OSGameLoaded.Replace("$1", Text.Linux), Visible = false }; - - private CheckBox macCheckBox = new CheckBox() { Text = Text.SupportsOS.Replace("$1", Text.Mac) }; - private Button macButton = new Button() { Text = Text.LoadOSZip.Replace("$1", Text.Mac), Enabled = false }; - private Label macLabel = new Label() { Text = Text.OSGameLoaded.Replace("$1", Text.Mac), Visible = false }; - - private Button originalZipButton = new Button() { Text = Text.LoadAM2R11 }; - private Label originalZipLabel = new Label() { Text = Text.AM2R11Loaded, Visible = false}; - private Button createButton = new Button() { Text = Text.CreateModPackage, Enabled = false }; - private Label createLabel = new Label() { Text = Text.ModPackageCreated, Visible = false}; + private CheckBox linuxCheckBox = new CheckBox(); + private Button linuxButton = new Button() { Enabled = false }; + private Label linuxLabel = new Label() { Visible = false }; + + private CheckBox macCheckBox = new CheckBox(); + private Button macButton = new Button() { Enabled = false }; + private Label macLabel = new Label() { Visible = false }; + + private Button originalZipButton = new Button(); + private Label originalZipLabel = new Label() { Visible = false }; + private Button createButton = new Button() { Enabled = false }; + private Label createLabel = new Label() { Visible = false }; #endregion } \ No newline at end of file diff --git a/Atomic/ModPacker.cs b/Atomic/ModPacker.cs index ed02b61..662819f 100644 --- a/Atomic/ModPacker.cs +++ b/Atomic/ModPacker.cs @@ -259,6 +259,26 @@ public partial class ModPacker : Form createLabel.Text = "Mod package(s) created!"; } + private void ModPacker_Closing(object sender, EventArgs e) + { + if (currentConfig.FillInContents) + { + currentConfig.Fields.ModName = nameTextBox.Text; + currentConfig.Fields.Author = authorTextBox.Text; + currentConfig.Fields.Version = versionTextBox.Text; + currentConfig.Fields.Notes = modNotesTextBox.Text; + currentConfig.Fields.UsesCustomSave = customSaveCheckBox.Checked.Value; + currentConfig.Fields.CustomSaveDir = customSaveTextBox.Text; + currentConfig.Fields.UsesCustomMusic = musicCheckBox.Checked.Value; + currentConfig.Fields.UsesYYC = yycCheckBox.Checked.Value; + currentConfig.Fields.SupportsWindows = windowsCheckBox.Checked.Value; + currentConfig.Fields.SupportsLinux = linuxCheckBox.Checked.Value; + currentConfig.Fields.SupportsMac = macCheckBox.Checked.Value; + currentConfig.Fields.SupportsAndroid = apkCheckBox.Checked.Value; + } + Config.SaveConfig(currentConfig); + } + private static string GetLocalizedStringOfOS(ProfileOperatingSystems os) { return os switch diff --git a/Atomic/SettingsForm.cs b/Atomic/SettingsForm.cs index efa8dc1..ee8230b 100644 --- a/Atomic/SettingsForm.cs +++ b/Atomic/SettingsForm.cs @@ -9,8 +9,10 @@ namespace Atomic; public class SettingsForm : Dialog { - public SettingsForm() + + public SettingsForm(Config config) { + currentConfig = config; Title = Text.SettingsTitle; Icon = new Icon(1f, new Bitmap(Resources.icon64)); Resizable = true; @@ -31,21 +33,29 @@ public class SettingsForm : Dialog "中文(简体)" }; - var langdropDown = new DropDown() { DataStore = languageList }; - langdropDown.SelectedIndexChanged += (sender, args) => - { - // TODO: save new setting - }; + languageDropDown = new DropDown() { DataStore = languageList }; + languageDropDown.SelectedKey = currentConfig.Language == "SystemLanguage" ? Text.SystemLanguage : currentConfig.Language; - var fillInContents = new CheckBox() { Text = Text.RememberFields }; - fillInContents.CheckedChanged += (sender, args) => - { - // TODO: save new setting - }; + fillInContents = new CheckBox() { Text = Text.RememberFields }; + fillInContents.Checked = currentConfig.FillInContents; - layout.AddRange(Text.LanguageNotice, langdropDown, fillInContents); + this.Closing += SettingsForm_Closing; + + layout.AddRange(Text.LanguageNotice, languageDropDown, fillInContents); //layout.AddSpace(); Content = layout; } + + private void SettingsForm_Closing(object sender, EventArgs e) + { + currentConfig.Language = languageDropDown.SelectedKey == Text.SystemLanguage ? "SystemLanguage" : languageDropDown.SelectedKey; + currentConfig.FillInContents = fillInContents.Checked.Value; + Config.SaveConfig(currentConfig); + } + + private Config currentConfig; + private DropDown languageDropDown; + private CheckBox fillInContents; + } \ No newline at end of file diff --git a/AtomicLib/Config.cs b/AtomicLib/Config.cs new file mode 100644 index 0000000..2c3081c --- /dev/null +++ b/AtomicLib/Config.cs @@ -0,0 +1,81 @@ +using System.Xml.Serialization; +using AtomicLib.XML; + +namespace AtomicLib; + +/// +/// Class that handles saving and loading the modpacker configuration. +/// +[Serializable] +[XmlRoot("config")] +public class Config +{ + public static string ConfigFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Atomic", "config.xml"); + + /// + /// Language used for the modpacker. + /// + [XmlAttribute("Language")] + public string Language + { get; set; } + + /// + /// Determines if the modpacker should remember information entered into the fields between usages. + /// + [XmlAttribute("FillInContents")] + public bool FillInContents + { get; set; } + + /// + /// Used to save information from the fields. Only used when is + /// + [XmlElement("Fields")] + public FieldContents Fields + { get; set; } + + public Config() + { + + } + + public Config(string language, bool fillIn) + { + Language = language; + FillInContents = fillIn; + Fields = new FieldContents(); + } + + /// + /// Reads the configuration from disk and returns a object. If the configuration does not exist, a default configuration will be created. + /// + /// Returns a object containing either the configuration read from disk or the default one. + public static Config LoadAndReturnConfig() + { + if (!File.Exists(ConfigFilePath)) + return CreateAndReturnDefaultConfig(); + + return Serializer.Deserialize(File.ReadAllText(ConfigFilePath)); + } + + /// + /// Saves a default configuration to disk and returns it, creating the config folders if necessary. + /// + /// Returns the object. + public static Config CreateAndReturnDefaultConfig() + { + Directory.CreateDirectory(Path.GetDirectoryName(ConfigFilePath)); + Config defaultConfig = new Config("SystemLanguage", true); + SaveConfig(defaultConfig); + return defaultConfig; + } + + /// + /// Writes the to disk. + /// + /// The that should be saved to the disk. + public static void SaveConfig(Config config) + { + string xmlOutput = Serializer.Serialize(config); + File.WriteAllText(ConfigFilePath, xmlOutput); + } +} \ No newline at end of file diff --git a/AtomicLib/FieldContents.cs b/AtomicLib/FieldContents.cs new file mode 100644 index 0000000..5d5318d --- /dev/null +++ b/AtomicLib/FieldContents.cs @@ -0,0 +1,68 @@ +using System.Reflection; +using System.Xml.Serialization; +using AtomicLib.XML; + +namespace AtomicLib; + +/// +/// Class that handles how field information is saved as XML. +/// +[Serializable] +[XmlRoot("fieldcontents")] + +public class FieldContents +{ + /// The text entered into a field for the mod name. + [XmlAttribute("ModName")] + public string ModName + { get; set; } + /// The text entered into a field for the mod author. + [XmlAttribute("Author")] + public string Author + { get; set; } + /// The text entered into a field for the mod version. + [XmlAttribute("Version")] + public string Version + { get; set; } + /// The text entered into a field for the mod notes. + [XmlAttribute("Notes")] + public string Notes + { get; set; } + /// The checkbox that indicates if the mod uses custom saves. + [XmlAttribute("UsesCustomSave")] + public bool UsesCustomSave + { get; set; } + /// The text that indicates the path used to store the mod's custom saves. + [XmlAttribute("CustomSaveDir")] + public string CustomSaveDir + { get; set; } + /// The checkbox that indicates if the mod uses custom music. + [XmlAttribute("UsesCustomMusic")] + public bool UsesCustomMusic + { get; set; } + /// The checkbox that indicates if the mod uses the YoYo Compiler. + [XmlAttribute("UsesYYC")] + public bool UsesYYC + { get; set; } + /// The checkbox that indicates if the mod supports Windows + [XmlAttribute("SupportsWindows")] + public bool SupportsWindows + { get; set; } + /// The checkbox that indicates if the mod supports Linux + [XmlAttribute("SupportsLinux")] + public bool SupportsLinux + { get; set; } + /// The checkbox that indicates if the mod supports Mac + [XmlAttribute("SupportsMac")] + public bool SupportsMac + { get; set; } + /// The checkbox that indicates if the mod supports Android + [XmlAttribute("SupportsAndroid")] + public bool SupportsAndroid + { get; set; } + + public FieldContents() + { + + } +} \ No newline at end of file