Mesen2/UI/Config/Configuration.cs

324 lines
9.6 KiB
C#

using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Mesen.Config.Shortcuts;
using Mesen.Utilities;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
namespace Mesen.Config
{
public partial class Configuration : ReactiveObject
{
private string _fileData = "";
public string Version { get; set; } = "2.0.0";
public int ConfigUpgrade { get; set; } = 0;
[Reactive] public VideoConfig Video { get; set; } = new();
[Reactive] public AudioConfig Audio { get; set; } = new();
[Reactive] public InputConfig Input { get; set; } = new();
[Reactive] public EmulationConfig Emulation { get; set; } = new();
[Reactive] public SnesConfig Snes { get; set; } = new();
[Reactive] public NesConfig Nes { get; set; } = new();
[Reactive] public GameboyConfig Gameboy { get; set; } = new();
[Reactive] public PcEngineConfig PcEngine { get; set; } = new();
[Reactive] public SmsConfig Sms { get; set; } = new();
[Reactive] public CvConfig Cv { get; set; } = new();
[Reactive] public GbaConfig Gba { get; set; } = new();
[Reactive] public WsConfig Ws { get; set; } = new();
[Reactive] public PreferencesConfig Preferences { get; set; } = new();
[Reactive] public AudioPlayerConfig AudioPlayer { get; set; } = new();
[Reactive] public DebugConfig Debug { get; set; } = new();
[Reactive] public RecentItems RecentFiles { get; set; } = new();
[Reactive] public VideoRecordConfig VideoRecord { get; set; } = new();
[Reactive] public MovieRecordConfig MovieRecord { get; set; } = new();
[Reactive] public HdPackBuilderConfig HdPackBuilder { get; set; } = new();
[Reactive] public CheatWindowConfig Cheats { get; set; } = new();
[Reactive] public NetplayConfig Netplay { get; set; } = new();
[Reactive] public HistoryViewerConfig HistoryViewer { get; set; } = new();
[Reactive] public MainWindowConfig MainWindow { get; set; } = new();
public DefaultKeyMappingType DefaultKeyMappings { get; set; } = DefaultKeyMappingType.Xbox | DefaultKeyMappingType.ArrowKeys;
public Configuration()
{
//Used by JSON deserializer, don't call directly - use CreateConfig
}
public static Configuration CreateConfig()
{
Configuration cfg = new();
cfg.ConfigUpgrade = (int)ConfigUpgradeHint.FirstRun;
return cfg;
}
~Configuration()
{
//Try to save before destruction if we were unable to save at a previous point in time
Save();
}
public void Save()
{
if(ConfigManager.DisableSaveSettings) {
//Don't save to disk if command line option to disable setting updates was set
return;
}
Serialize(ConfigManager.ConfigFile);
}
public void ApplyConfig()
{
Video.ApplyConfig();
Audio.ApplyConfig();
Input.ApplyConfig();
Emulation.ApplyConfig();
Gameboy.ApplyConfig();
Gba.ApplyConfig();
PcEngine.ApplyConfig();
Nes.ApplyConfig();
Snes.ApplyConfig();
Sms.ApplyConfig();
Cv.ApplyConfig();
Ws.ApplyConfig();
Preferences.ApplyConfig();
AudioPlayer.ApplyConfig();
Debug.ApplyConfig();
}
public void InitializeFontDefaults()
{
if(ConfigUpgrade == (int)ConfigUpgradeHint.FirstRun) {
Preferences.InitializeFontDefaults();
Debug.Fonts.DisassemblyFont = GetDefaultMonospaceFont();
Debug.Fonts.MemoryViewerFont = GetDefaultMonospaceFont();
Debug.Fonts.AssemblerFont = GetDefaultMonospaceFont();
Debug.Fonts.ScriptWindowFont = GetDefaultMonospaceFont();
Debug.Fonts.OtherMonoFont = GetDefaultMonospaceFont(true);
Debug.Fonts.ApplyConfig();
}
}
public void UpgradeConfig()
{
if(ConfigUpgrade < (int)ConfigUpgradeHint.SmsInput) {
Sms.InitializeDefaults(DefaultKeyMappings);
}
if(ConfigUpgrade < (int)ConfigUpgradeHint.GbaInput) {
Gba.InitializeDefaults(DefaultKeyMappings);
}
if(ConfigUpgrade < (int)ConfigUpgradeHint.CvInput) {
Cv.InitializeDefaults(DefaultKeyMappings);
}
if(ConfigUpgrade < (int)ConfigUpgradeHint.WsInput) {
Ws.InitializeDefaults(DefaultKeyMappings);
}
ConfigUpgrade = (int)ConfigUpgradeHint.NextValue - 1;
}
public void InitializeDefaults()
{
if(ConfigUpgrade == (int)ConfigUpgradeHint.FirstRun) {
Snes.InitializeDefaults(DefaultKeyMappings);
Nes.InitializeDefaults(DefaultKeyMappings);
Gameboy.InitializeDefaults(DefaultKeyMappings);
Gba.InitializeDefaults(DefaultKeyMappings);
PcEngine.InitializeDefaults(DefaultKeyMappings);
Sms.InitializeDefaults(DefaultKeyMappings);
Cv.InitializeDefaults(DefaultKeyMappings);
Ws.InitializeDefaults(DefaultKeyMappings);
ConfigUpgrade = (int)ConfigUpgradeHint.NextValue - 1;
}
Preferences.InitializeDefaultShortcuts();
}
private static HashSet<string>? _installedFonts = null;
private static List<string>? _sortedFonts = null;
[MemberNotNull(nameof(_installedFonts), nameof(_sortedFonts))]
private static void InitInstalledFonts()
{
_installedFonts = new();
_sortedFonts = new();
try {
int count = FontManager.Current.SystemFonts.Count;
for(int i = 0; i < count; i++) {
try {
string? fontName = FontManager.Current.SystemFonts[i]?.Name;
if(!string.IsNullOrWhiteSpace(fontName)) {
_installedFonts.Add(fontName);
}
} catch { }
}
_sortedFonts.AddRange(_installedFonts);
_sortedFonts.Sort();
} catch {
}
}
public static List<string> GetSortedFontList()
{
if(_sortedFonts == null) {
InitInstalledFonts();
}
return new List<string>(_sortedFonts);
}
private static string FindMatchingFont(string defaultFont, params string[] fontNames)
{
if(_installedFonts == null) {
InitInstalledFonts();
}
foreach(string name in fontNames) {
if(_installedFonts.Contains(name)) {
return name;
}
}
return defaultFont;
}
public static string GetValidFontFamily(string requestedFont, bool preferMonoFont)
{
if(_installedFonts == null) {
InitInstalledFonts();
}
if(_installedFonts.Contains(requestedFont)) {
return requestedFont;
}
foreach(string name in _installedFonts) {
if(preferMonoFont && name.Contains("Mono", StringComparison.InvariantCultureIgnoreCase)) {
return name;
} else if(!preferMonoFont && name.Contains("Sans", StringComparison.InvariantCultureIgnoreCase)) {
return name;
}
}
return _installedFonts.First();
}
public static FontConfig GetDefaultFont()
{
if(OperatingSystem.IsWindows()) {
return new FontConfig() { FontFamily = "Microsoft Sans Serif", FontSize = 11 };
} else if(OperatingSystem.IsMacOS()) {
return new FontConfig() { FontFamily = FindMatchingFont("Microsoft Sans Serif"), FontSize = 11 };
} else {
return new FontConfig() { FontFamily = FindMatchingFont("FreeSans", "DejaVu Sans", "Noto Sans"), FontSize = 11 };
}
}
public static FontConfig GetDefaultMenuFont()
{
if(OperatingSystem.IsWindows()) {
return new FontConfig() { FontFamily = "Segoe UI", FontSize = 12 };
} else if(OperatingSystem.IsMacOS()) {
return new FontConfig() { FontFamily = FindMatchingFont("Microsoft Sans Serif"), FontSize = 12 };
} else {
return new FontConfig() { FontFamily = FindMatchingFont("FreeSans", "DejaVu Sans", "Noto Sans"), FontSize = 12 };
}
}
public static FontConfig GetDefaultMonospaceFont(bool useSmallFont = false)
{
if(OperatingSystem.IsWindows()) {
return new FontConfig() { FontFamily = "Consolas", FontSize = useSmallFont ? 12 : 14 };
} else if(OperatingSystem.IsMacOS()) {
return new FontConfig() { FontFamily = FindMatchingFont("PT Mono"), FontSize = useSmallFont ? 11 : 12 };
} else {
return new FontConfig() { FontFamily = FindMatchingFont("FreeMono", "DejaVu Sans Mono", "Noto Sans Mono"), FontSize = 12 };
}
}
public static Configuration Deserialize(string configFile)
{
Configuration config;
try {
string fileData = File.ReadAllText(configFile);
config = (Configuration?)JsonSerializer.Deserialize(fileData, typeof(Configuration), MesenSerializerContext.Default) ?? Configuration.CreateConfig();
config._fileData = fileData;
} catch {
try {
//File exists but couldn't be loaded, make a backup of the old settings before we overwrite them
BackupSettings(configFile);
} catch { }
config = Configuration.CreateConfig();
}
return config;
}
public static void BackupSettings(string configFile)
{
//File exists but couldn't be loaded, make a backup of the old settings before we overwrite them
string? folder = Path.GetDirectoryName(configFile);
if(folder != null) {
File.Copy(configFile, Path.Combine(folder, "settings." + DateTime.Now.ToString("yyyy-M-dd_HH-mm-ss") + ".bak"), true);
}
}
public void Serialize(string configFile)
{
try {
string cfgData = JsonSerializer.Serialize(this, typeof(Configuration), MesenSerializerContext.Default);
if(_fileData != cfgData && !Design.IsDesignMode) {
FileHelper.WriteAllText(configFile, cfgData);
_fileData = cfgData;
}
} catch {
//This can sometime fail due to the file being used by another Mesen instance, etc.
}
}
public void RemoveObsoleteConfig()
{
//Clean up configuration to remove any obsolete values that existed in older versions
for(int i = Preferences.ShortcutKeys.Count - 1; i >= 0; i--) {
if(Preferences.ShortcutKeys[i].Shortcut >= EmulatorShortcut.LastValidValue) {
Preferences.ShortcutKeys.RemoveAt(i);
}
}
}
}
[Flags]
public enum DefaultKeyMappingType
{
None = 0,
Xbox = 1,
Ps4 = 2,
WasdKeys = 4,
ArrowKeys = 8
}
public enum ConfigUpgradeHint
{
Uninitialized = 0,
FirstRun,
SmsInput,
GbaInput,
CvInput,
WsInput,
NextValue,
}
}