Files
SpineViewer/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
2025-09-27 23:43:54 +08:00

342 lines
12 KiB
C#

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Win32;
using NLog;
using Spine.SpineWrappers;
using SpineViewer.Models;
using SpineViewer.Natives;
using SpineViewer.Services;
using SpineViewer.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace SpineViewer.ViewModels.MainWindow
{
public class PreferenceViewModel : ObservableObject
{
/// <summary>
/// 文件保存路径
/// </summary>
public static readonly string PreferenceFilePath = Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "preference.json");
private static readonly string SkelFileDescription = "SpineViewer File";
private static readonly string SkelIconFilePath = Path.Combine(App.ProcessDirectory, "Resources\\Images\\skel.ico");
private static readonly string ShellOpenCommand = $"\"{App.ProcessPath}\" \"%1\"";
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly MainWindowViewModel _vmMain;
public PreferenceViewModel(MainWindowViewModel vmMain)
{
_vmMain = vmMain;
}
/// <summary>
/// 显示首选项对话框
/// </summary>
public RelayCommand Cmd_ShowPreferenceDialog => _cmd_ShowPreferenceDialog ??= new(ShowPreferenceDialog_Execute);
private RelayCommand? _cmd_ShowPreferenceDialog;
private void ShowPreferenceDialog_Execute()
{
var m = Preference;
if (!DialogService.ShowPreferenceDialog(m))
return;
Preference = m;
SavePreference(m);
}
private static void SavePreference(PreferenceModel m)
{
JsonHelper.Serialize(m, PreferenceFilePath);
}
/// <summary>
/// 保存首选项, 保存失败会有日志提示
/// </summary>
public void SavePreference() => SavePreference(Preference);
/// <summary>
/// 加载首选项, 加载失败会有日志提示
/// </summary>
public void LoadPreference()
{
if (JsonHelper.Deserialize<PreferenceModel>(PreferenceFilePath, out var obj, true))
{
try
{
Preference = obj;
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_logger.Error("Failed to load some prefereneces, {0}", ex.Message);
}
}
}
/// <summary>
/// 获取参数副本或者进行设置
/// </summary>
private PreferenceModel Preference
{
get
{
return new()
{
ForcePremul = ForcePremul,
ForceNearest = ForceNearest,
ForceMipmap = ForceMipmap,
IsShown = IsShown,
UsePma = UsePma,
DebugTexture = DebugTexture,
DebugBounds = DebugBounds,
DebugBones = DebugBones,
DebugRegions = DebugRegions,
DebugMeshHulls = DebugMeshHulls,
DebugMeshes = DebugMeshes,
DebugBoundingBoxes = DebugBoundingBoxes,
DebugPaths = DebugPaths,
DebugPoints = DebugPoints,
DebugClippings = DebugClippings,
WallpaperView = WallpaperView,
RenderSelectedOnly = RenderSelectedOnly,
AssociateFileSuffix = AssociateFileSuffix,
AppLanguage = AppLanguage,
};
}
set
{
ForcePremul = value.ForcePremul;
ForceNearest = value.ForceNearest;
ForceMipmap = value.ForceMipmap;
IsShown = value.IsShown;
UsePma = value.UsePma;
DebugTexture = value.DebugTexture;
DebugBounds = value.DebugBounds;
DebugBones = value.DebugBones;
DebugRegions = value.DebugRegions;
DebugMeshHulls = value.DebugMeshHulls;
DebugMeshes = value.DebugMeshes;
DebugBoundingBoxes = value.DebugBoundingBoxes;
DebugPaths = value.DebugPaths;
DebugPoints = value.DebugPoints;
DebugClippings = value.DebugClippings;
WallpaperView = value.WallpaperView;
RenderSelectedOnly = value.RenderSelectedOnly;
AssociateFileSuffix = value.AssociateFileSuffix;
AppLanguage = value.AppLanguage;
}
}
#region
public bool ForcePremul
{
get => TextureLoader.DefaultLoader.ForcePremul;
set => SetProperty(TextureLoader.DefaultLoader.ForcePremul, value, v => TextureLoader.DefaultLoader.ForcePremul = v);
}
public bool ForceNearest
{
get => TextureLoader.DefaultLoader.ForceNearest;
set => SetProperty(TextureLoader.DefaultLoader.ForceNearest, value, v => TextureLoader.DefaultLoader.ForceNearest = v);
}
public bool ForceMipmap
{
get => TextureLoader.DefaultLoader.ForceMipmap;
set => SetProperty(TextureLoader.DefaultLoader.ForceMipmap, value, v => TextureLoader.DefaultLoader.ForceMipmap = v);
}
#endregion
#region
public bool IsShown
{
get => SpineObjectModel.LoadOptions.IsShown;
set => SetProperty(SpineObjectModel.LoadOptions.IsShown, value, v => SpineObjectModel.LoadOptions.IsShown = v);
}
public bool UsePma
{
get => SpineObjectModel.LoadOptions.UsePma;
set => SetProperty(SpineObjectModel.LoadOptions.UsePma, value, v => SpineObjectModel.LoadOptions.UsePma = v);
}
public bool DebugTexture
{
get => SpineObjectModel.LoadOptions.DebugTexture;
set => SetProperty(SpineObjectModel.LoadOptions.DebugTexture, value, v => SpineObjectModel.LoadOptions.DebugTexture = v);
}
public bool DebugBounds
{
get => SpineObjectModel.LoadOptions.DebugBounds;
set => SetProperty(SpineObjectModel.LoadOptions.DebugBounds, value, v => SpineObjectModel.LoadOptions.DebugBounds = v);
}
public bool DebugBones
{
get => SpineObjectModel.LoadOptions.DebugBones;
set => SetProperty(SpineObjectModel.LoadOptions.DebugBones, value, v => SpineObjectModel.LoadOptions.DebugBones = v);
}
public bool DebugRegions
{
get => SpineObjectModel.LoadOptions.DebugRegions;
set => SetProperty(SpineObjectModel.LoadOptions.DebugRegions, value, v => SpineObjectModel.LoadOptions.DebugRegions = v);
}
public bool DebugMeshHulls
{
get => SpineObjectModel.LoadOptions.DebugMeshHulls;
set => SetProperty(SpineObjectModel.LoadOptions.DebugMeshHulls, value, v => SpineObjectModel.LoadOptions.DebugMeshHulls = v);
}
public bool DebugMeshes
{
get => SpineObjectModel.LoadOptions.DebugMeshes;
set => SetProperty(SpineObjectModel.LoadOptions.DebugMeshes, value, v => SpineObjectModel.LoadOptions.DebugMeshes = v);
}
public bool DebugBoundingBoxes
{
get => SpineObjectModel.LoadOptions.DebugBoundingBoxes;
set => SetProperty(SpineObjectModel.LoadOptions.DebugBoundingBoxes, value, v => SpineObjectModel.LoadOptions.DebugBoundingBoxes = v);
}
public bool DebugPaths
{
get => SpineObjectModel.LoadOptions.DebugPaths;
set => SetProperty(SpineObjectModel.LoadOptions.DebugPaths, value, v => SpineObjectModel.LoadOptions.DebugPaths = v);
}
public bool DebugPoints
{
get => SpineObjectModel.LoadOptions.DebugPoints;
set => SetProperty(SpineObjectModel.LoadOptions.DebugPoints, value, v => SpineObjectModel.LoadOptions.DebugPoints = v);
}
public bool DebugClippings
{
get => SpineObjectModel.LoadOptions.DebugClippings;
set => SetProperty(SpineObjectModel.LoadOptions.DebugClippings, value, v => SpineObjectModel.LoadOptions.DebugClippings = v);
}
#endregion
#region
public static ImmutableArray<AppLanguage> AppLanguageOptions { get; } = Enum.GetValues<AppLanguage>().ToImmutableArray();
public bool AutoRun
{
get => throw new NotImplementedException();
set => throw new NotImplementedException();
}
public bool WallpaperView
{
get => _wallpaperView;
set => SetProperty(ref _wallpaperView, value);
}
private bool _wallpaperView; // UI 变化通过 PropertyChanged 事件交由 View 层处理
public bool RenderSelectedOnly
{
get => _vmMain.SFMLRendererViewModel.RenderSelectedOnly;
set => SetProperty(_vmMain.SFMLRendererViewModel.RenderSelectedOnly, value, v => _vmMain.SFMLRendererViewModel.RenderSelectedOnly = v);
}
public bool AssociateFileSuffix
{
get
{
try
{
// 检查 .skel 的 ProgID
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Classes\.skel"))
{
var progIdValue = key?.GetValue("") as string;
if (!string.Equals(progIdValue, App.ProgId, StringComparison.OrdinalIgnoreCase))
return false;
}
// 检查 command 指令是否相同
using (var key = Registry.CurrentUser.OpenSubKey($@"Software\Classes\{App.ProgId}\shell\open\command"))
{
var command = key?.GetValue("") as string;
if (string.IsNullOrWhiteSpace(command))
return false;
return command == ShellOpenCommand;
}
}
catch
{
return false;
}
}
set
{
SetProperty(AssociateFileSuffix, value, v =>
{
if (v)
{
// 文件关联
using (var key = Registry.CurrentUser.CreateSubKey(@"Software\Classes\.skel"))
{
key?.SetValue("", App.ProgId);
}
using (var key = Registry.CurrentUser.CreateSubKey($@"Software\Classes\{App.ProgId}"))
{
key?.SetValue("", SkelFileDescription);
using (var iconKey = key?.CreateSubKey("DefaultIcon"))
{
iconKey?.SetValue("", $"\"{SkelIconFilePath}\"");
}
using (var shellKey = key?.CreateSubKey(@"shell\open\command"))
{
shellKey?.SetValue("", ShellOpenCommand);
}
}
}
else
{
// 删除关联
Registry.CurrentUser.DeleteSubKeyTree(@"Software\Classes\.skel", false);
Registry.CurrentUser.DeleteSubKeyTree($@"Software\Classes\{App.ProgId}", false);
}
Shell32.NotifyAssociationChanged();
});
}
}
public AppLanguage AppLanguage
{
get => ((App)App.Current).Language;
set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v);
}
#endregion
}
}