增加首选项对话框
This commit is contained in:
106
SpineViewer/Models/PreferenceModel.cs
Normal file
106
SpineViewer/Models/PreferenceModel.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Spine.SpineWrappers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace SpineViewer.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// 首选项参数模型, 用于对话框修改以及本地保存
|
||||
/// </summary>
|
||||
public partial class PreferenceModel : ObservableObject
|
||||
{
|
||||
#region 纹理加载首选项
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _forcePremul;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _forceNearest;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _forceMipmap;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 模型加载首选项
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _usePma;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugTexture = true;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugBounds;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugBones;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugRegions;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugMeshHulls;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugMeshes;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugBoundingBoxes;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugPaths;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugPoints;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _debugClippings;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 序列化与反序列
|
||||
|
||||
/// <summary>
|
||||
/// 保存 Json 文件的格式参数
|
||||
/// </summary>
|
||||
private static readonly JsonSerializerOptions _jsonOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 从文件反序列对象, 可能抛出异常
|
||||
/// </summary>
|
||||
public static PreferenceModel Deserialize(string path)
|
||||
{
|
||||
if (!File.Exists(path)) throw new FileNotFoundException("Preference file not found", path);
|
||||
var json = File.ReadAllText(path, Encoding.UTF8);
|
||||
var model = JsonSerializer.Deserialize<PreferenceModel>(json, _jsonOptions);
|
||||
return model ?? throw new JsonException($"null data in file '{path}'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存至文件, 可能抛出异常
|
||||
/// </summary>
|
||||
public void Serialize(string path)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
var json = JsonSerializer.Serialize(this, _jsonOptions);
|
||||
File.WriteAllText(path, json, Encoding.UTF8);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,8 @@
|
||||
<s:String x:Key="Str_Experiment">Experimental Features</s:String>
|
||||
|
||||
<s:String x:Key="Str_Open">Open...</s:String>
|
||||
<s:String x:Key="Str_Preference">Preferences...</s:String>
|
||||
<s:String x:Key="Str_Preference">Preferences</s:String>
|
||||
<s:String x:Key="Str_PreferenceWithDots">Preferences...</s:String>
|
||||
<s:String x:Key="Str_Exit">Exit</s:String>
|
||||
|
||||
<!-- 标签页 -->
|
||||
@@ -194,4 +195,14 @@
|
||||
<s:String x:Key="Str_ProgremVersion">Program Version</s:String>
|
||||
<s:String x:Key="Str_ProjectUrl">Project URL</s:String>
|
||||
|
||||
<!-- 首选项对话框 -->
|
||||
<s:String x:Key="Str_TextureLoadPreference">Texture Loading Options</s:String>
|
||||
<s:String x:Key="Str_ForcePremul">Force Premultiplied Channels</s:String>
|
||||
<s:String x:Key="Str_ForcePremulTooltip">When enabled, this applies premultiplied operations to pixels during texture loading, helping to resolve black edge issues at some connections.</s:String>
|
||||
<s:String x:Key="Str_ForceNearest">Force Nearest Interpolation</s:String>
|
||||
<s:String x:Key="Str_ForceMipmap">Force Mipmap</s:String>
|
||||
<s:String x:Key="Str_ForceMipmapTooltip">When enabled, this helps reduce aliasing when textures are scaled down, at the cost of slightly higher video memory usage.</s:String>
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">Model Loading Options</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
<s:String x:Key="Str_Experiment">実験機能</s:String>
|
||||
|
||||
<s:String x:Key="Str_Open">開く...</s:String>
|
||||
<s:String x:Key="Str_Preference">設定...</s:String>
|
||||
<s:String x:Key="Str_Preference">設定</s:String>
|
||||
<s:String x:Key="Str_PreferenceWithDots">設定...</s:String>
|
||||
<s:String x:Key="Str_Exit">終了</s:String>
|
||||
|
||||
<!-- 标签页 -->
|
||||
@@ -194,5 +195,15 @@
|
||||
<s:String x:Key="Str_ProgremVersion">プログラムバージョン</s:String>
|
||||
<s:String x:Key="Str_ProjectUrl">プロジェクトURL</s:String>
|
||||
|
||||
<!-- 首选项对话框 -->
|
||||
<s:String x:Key="Str_TextureLoadPreference">テクスチャ読み込みオプション</s:String>
|
||||
<s:String x:Key="Str_ForcePremul">強制プリマルチチャンネル</s:String>
|
||||
<s:String x:Key="Str_ForcePremulTooltip">有効にすると、テクスチャ読み込み時にピクセルにプリマルチ処理を適用し、一部の接続部分で発生する黒い縁の問題を解決します。</s:String>
|
||||
<s:String x:Key="Str_ForceNearest">Nearest補間を強制使用</s:String>
|
||||
<s:String x:Key="Str_ForceMipmap">Mipmapを強制使用</s:String>
|
||||
<s:String x:Key="Str_ForceMipmapTooltip">有効にすると、テクスチャ縮小時のジャギーを軽減しますが、ビデオメモリの使用量が若干増加します。</s:String>
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">モデル読み込みオプション</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
<s:String x:Key="Str_Experiment">实验性功能</s:String>
|
||||
|
||||
<s:String x:Key="Str_Open">打开...</s:String>
|
||||
<s:String x:Key="Str_Preference">首选项...</s:String>
|
||||
<s:String x:Key="Str_Preference">首选项</s:String>
|
||||
<s:String x:Key="Str_PreferenceWithDots">首选项...</s:String>
|
||||
<s:String x:Key="Str_Exit">退出</s:String>
|
||||
|
||||
<!-- 标签页 -->
|
||||
@@ -194,4 +195,14 @@
|
||||
<s:String x:Key="Str_ProgremVersion">程序版本</s:String>
|
||||
<s:String x:Key="Str_ProjectUrl">项目地址</s:String>
|
||||
|
||||
<!-- 首选项对话框 -->
|
||||
<s:String x:Key="Str_TextureLoadPreference">纹理加载选项</s:String>
|
||||
<s:String x:Key="Str_ForcePremul">强制预乘通道</s:String>
|
||||
<s:String x:Key="Str_ForcePremulTooltip">开启后,会在加载纹理时对像素进行预乘操作,有助于解决某些情况下的连接处黑边问题</s:String>
|
||||
<s:String x:Key="Str_ForceNearest">强制使用 Nearest 插值</s:String>
|
||||
<s:String x:Key="Str_ForceMipmap">强制使用 Mipmap</s:String>
|
||||
<s:String x:Key="Str_ForceMipmapTooltip">开启后有助于改善纹理缩小时的锯齿现象,但是会略微增加显存占用</s:String>
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">模型加载选项</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Win32;
|
||||
using SpineViewer.Models;
|
||||
using SpineViewer.ViewModels.Exporters;
|
||||
using SpineViewer.Views;
|
||||
using SpineViewer.Views.ExporterDialogs;
|
||||
@@ -51,6 +52,15 @@ namespace SpineViewer.Services
|
||||
return dialog.ShowDialog() ?? false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将给定的首选项参数在对话框上进行显示, 返回值表示是否确认修改
|
||||
/// </summary>
|
||||
public static bool ShowPreferenceDialog(PreferenceModel m)
|
||||
{
|
||||
var dialog = new PreferenceDialog() { DataContext = m, Owner = App.Current.MainWindow };
|
||||
return dialog.ShowDialog() ?? false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户选择的文件夹
|
||||
/// </summary>
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
_explorerListViewModel = new(this);
|
||||
_spineObjectListViewModel = new(this);
|
||||
_sfmlRendererViewModel = new(this);
|
||||
_preferenceViewModel = new(this);
|
||||
}
|
||||
|
||||
public string Title => $"SpineViewer - v{App.Version}";
|
||||
@@ -56,6 +57,9 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
public ObservableCollectionWithLock<SpineObjectModel> SpineObjects => _spineObjectModels;
|
||||
private readonly ObservableCollectionWithLock<SpineObjectModel> _spineObjectModels = [];
|
||||
|
||||
public PreferenceViewModel PreferenceViewModel => _preferenceViewModel;
|
||||
private readonly PreferenceViewModel _preferenceViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 浏览页列表 ViewModel
|
||||
/// </summary>
|
||||
|
||||
191
SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
Normal file
191
SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using NLog;
|
||||
using Spine.SpineWrappers;
|
||||
using SpineViewer.Models;
|
||||
using SpineViewer.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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 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)
|
||||
{
|
||||
try
|
||||
{
|
||||
m.Serialize(PreferenceFilePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("Failed to save preference to {0}, {1}", PreferenceFilePath, ex.Message);
|
||||
_logger.Trace(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存首选项, 保存失败会有日志提示
|
||||
/// </summary>
|
||||
public void SavePreference() => SavePreference(Preference);
|
||||
|
||||
/// <summary>
|
||||
/// 加载首选项, 加载失败会有日志提示
|
||||
/// </summary>
|
||||
public void LoadPreference()
|
||||
{
|
||||
if (!File.Exists(PreferenceFilePath)) return;
|
||||
|
||||
try
|
||||
{
|
||||
var m = PreferenceModel.Deserialize(PreferenceFilePath);
|
||||
Preference = m;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("Failed to load preference from {0}, {1}", PreferenceFilePath, ex.Message);
|
||||
_logger.Trace(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取参数副本或者进行设置
|
||||
/// </summary>
|
||||
private PreferenceModel Preference
|
||||
{
|
||||
get
|
||||
{
|
||||
return new()
|
||||
{
|
||||
ForcePremul = ForcePremul,
|
||||
ForceNearest = ForceNearest,
|
||||
ForceMipmap = ForceMipmap,
|
||||
UsePma = UsePma,
|
||||
DebugTexture = DebugTexture,
|
||||
DebugBounds = DebugBounds,
|
||||
DebugBones = DebugBones,
|
||||
DebugRegions = DebugRegions,
|
||||
DebugMeshHulls = DebugMeshHulls,
|
||||
DebugMeshes = DebugMeshes,
|
||||
DebugBoundingBoxes = DebugBoundingBoxes,
|
||||
DebugPaths = DebugPaths,
|
||||
DebugPoints = DebugPoints,
|
||||
DebugClippings = DebugClippings
|
||||
};
|
||||
}
|
||||
set
|
||||
{
|
||||
ForcePremul = value.ForcePremul;
|
||||
ForceNearest = value.ForceNearest;
|
||||
ForceMipmap = value.ForceMipmap;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
// TODO: 是否自动记忆模型参数
|
||||
|
||||
#region 模型加载首选项
|
||||
|
||||
public bool UsePma { get => _usePma; set => SetProperty(ref _usePma, value); }
|
||||
private bool _usePma;
|
||||
|
||||
public bool DebugTexture { get => _debugTexture; set => SetProperty(ref _debugTexture, value); }
|
||||
private bool _debugTexture = true;
|
||||
|
||||
public bool DebugBounds { get => _debugBounds; set => SetProperty(ref _debugBounds, value); }
|
||||
private bool _debugBounds;
|
||||
|
||||
public bool DebugBones { get => _debugBones; set => SetProperty(ref _debugBones, value); }
|
||||
private bool _debugBones;
|
||||
|
||||
public bool DebugRegions { get => _debugRegions; set => SetProperty(ref _debugRegions, value); }
|
||||
private bool _debugRegions;
|
||||
|
||||
public bool DebugMeshHulls { get => _debugMeshHulls; set => SetProperty(ref _debugMeshHulls, value); }
|
||||
private bool _debugMeshHulls;
|
||||
|
||||
public bool DebugMeshes { get => _debugMeshes; set => SetProperty(ref _debugMeshes, value); }
|
||||
private bool _debugMeshes;
|
||||
|
||||
public bool DebugBoundingBoxes { get => _debugBoundingBoxes; set => SetProperty(ref _debugBoundingBoxes, value); }
|
||||
private bool _debugBoundingBoxes;
|
||||
|
||||
public bool DebugPaths { get => _debugPaths; set => SetProperty(ref _debugPaths, value); }
|
||||
private bool _debugPaths;
|
||||
|
||||
public bool DebugPoints { get => _debugPoints; set => SetProperty(ref _debugPoints, value); }
|
||||
private bool _debugPoints;
|
||||
|
||||
public bool DebugClippings { get => _debugClippings; set => SetProperty(ref _debugClippings, value); }
|
||||
private bool _debugClippings;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
|
||||
lock (_spineObjectModels.Lock)
|
||||
{
|
||||
// XXX: 这里必须要浅拷贝一次, 不能直接对会被修改的绑定数据 args 进行 foreach 遍历
|
||||
// NOTE: 这里必须要浅拷贝一次, 不能直接对会被修改的绑定数据 args 进行 foreach 遍历
|
||||
foreach (var sp in args.Cast<SpineObjectModel>().ToArray())
|
||||
{
|
||||
_spineObjectModels.Remove(sp);
|
||||
@@ -249,6 +249,41 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全地在末尾添加一个模型, 发生错误会输出日志
|
||||
/// </summary>
|
||||
/// <returns>是否添加成功</returns>
|
||||
public bool AddSpineObject(string skelPath, string? atlasPath = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: 判断是否记忆参数
|
||||
var pre = _vmMain.PreferenceViewModel;
|
||||
var sp = new SpineObjectModel(skelPath, atlasPath)
|
||||
{
|
||||
UsePma = pre.UsePma,
|
||||
DebugTexture = pre.DebugTexture,
|
||||
DebugBounds = pre.DebugBounds,
|
||||
DebugRegions = pre.DebugRegions,
|
||||
DebugMeshHulls = pre.DebugMeshHulls,
|
||||
DebugMeshes = pre.DebugMeshes,
|
||||
DebugBoundingBoxes = pre.DebugBoundingBoxes,
|
||||
DebugPaths = pre.DebugPaths,
|
||||
DebugPoints = pre.DebugPoints,
|
||||
DebugClippings = pre.DebugClippings
|
||||
};
|
||||
|
||||
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Trace(ex.ToString());
|
||||
_logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从路径列表添加对象
|
||||
/// </summary>
|
||||
@@ -289,17 +324,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
}
|
||||
else if (validPaths.Count > 0)
|
||||
{
|
||||
var skelPath = validPaths[0];
|
||||
try
|
||||
{
|
||||
var sp = new SpineObjectModel(skelPath);
|
||||
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Trace(ex.ToString());
|
||||
_logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message);
|
||||
}
|
||||
AddSpineObject(validPaths[0]);
|
||||
_logger.LogCurrentProcessMemoryUsage();
|
||||
}
|
||||
}
|
||||
@@ -326,18 +351,10 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
var skelPath = paths[i];
|
||||
reporter.ProgressText = $"[{i}/{totalCount}] {skelPath}";
|
||||
|
||||
try
|
||||
{
|
||||
var sp = new SpineObjectModel(skelPath);
|
||||
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
|
||||
if (AddSpineObject(skelPath))
|
||||
success++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Trace(ex.ToString());
|
||||
_logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message);
|
||||
else
|
||||
error++;
|
||||
}
|
||||
|
||||
reporter.Done = i + 1;
|
||||
reporter.ProgressText = $"[{i + 1}/{totalCount}] {skelPath}";
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<MenuItem Header="{DynamicResource Str_File}">
|
||||
<MenuItem Header="{DynamicResource Str_Open}" InputGestureText="Ctrl+O"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="{DynamicResource Str_Preference}"/>
|
||||
<MenuItem Header="{DynamicResource Str_PreferenceWithDots}" Command="{Binding PreferenceViewModel.Cmd_ShowPreferenceDialog}"/>
|
||||
<!--<MenuItem Header="{DynamicResource Str_Exit}" InputGestureText="Alt+F4"/>-->
|
||||
</MenuItem>
|
||||
<!--<MenuItem Header="{DynamicResource Str_Tool}"/>-->
|
||||
|
||||
@@ -61,6 +61,9 @@ public partial class MainWindow : Window
|
||||
vm.FlipY = true;
|
||||
vm.MaxFps = 30;
|
||||
vm.StartRender();
|
||||
|
||||
// 加载首选项
|
||||
_vm.PreferenceViewModel.LoadPreference();
|
||||
}
|
||||
|
||||
private void MainWindow_Closed(object? sender, EventArgs e)
|
||||
|
||||
132
SpineViewer/Views/PreferenceDialog.xaml
Normal file
132
SpineViewer/Views/PreferenceDialog.xaml
Normal file
@@ -0,0 +1,132 @@
|
||||
<Window xmlns:hc="https://handyorg.github.io/handycontrol" x:Class="SpineViewer.Views.PreferenceDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SpineViewer.Views"
|
||||
xmlns:models="clr-namespace:SpineViewer.Models"
|
||||
d:DataContext="{d:DesignInstance Type=models:PreferenceModel}"
|
||||
mc:Ignorable="d"
|
||||
Title="{DynamicResource Str_Preference}"
|
||||
Height="650"
|
||||
Width="600"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Bottom">
|
||||
<WrapPanel HorizontalAlignment="Center">
|
||||
<WrapPanel.Resources>
|
||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonDefault}">
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
<Setter Property="Width" Value="100"/>
|
||||
</Style>
|
||||
</WrapPanel.Resources>
|
||||
<Button Content="{DynamicResource Str_OK}" Click="ButtonOK_Click"/>
|
||||
<Button Content="{DynamicResource Str_Cancel}" Click="ButtonCancel_Click"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
|
||||
<Border>
|
||||
<Border.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource LabelDefault}">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextBoxBaseStyle}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
|
||||
</Style>
|
||||
</Border.Resources>
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Grid.IsSharedSizeScope="True">
|
||||
<GroupBox Header="{DynamicResource Str_TextureLoadPreference}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/>
|
||||
<ToggleButton Grid.Row="0" Grid.Column="1" IsChecked="{Binding ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ForceNearest}"/>
|
||||
<ToggleButton Grid.Row="1" Grid.Column="1" IsChecked="{Binding ForceNearest}"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/>
|
||||
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="{DynamicResource Str_SpineLoadPreference}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_UsePma}"/>
|
||||
<ToggleButton Grid.Row="0" Grid.Column="1" IsChecked="{Binding UsePma}"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_DebugTexture}"/>
|
||||
<ToggleButton Grid.Row="1" Grid.Column="1" IsChecked="{Binding DebugTexture}"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_DebugBounds}"/>
|
||||
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding DebugBounds}"/>
|
||||
|
||||
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_DebugBones}"/>
|
||||
<ToggleButton Grid.Row="3" Grid.Column="1" IsChecked="{Binding DebugBones}"/>
|
||||
|
||||
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_DebugRegions}"/>
|
||||
<ToggleButton Grid.Row="4" Grid.Column="1" IsChecked="{Binding DebugRegions}"/>
|
||||
|
||||
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_DebugMeshHulls}"/>
|
||||
<ToggleButton Grid.Row="5" Grid.Column="1" IsChecked="{Binding DebugMeshHulls}"/>
|
||||
|
||||
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource Str_DebugMeshes}"/>
|
||||
<ToggleButton Grid.Row="6" Grid.Column="1" IsChecked="{Binding DebugMeshes}"/>
|
||||
|
||||
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource Str_DebugBoundingBoxes}"/>
|
||||
<ToggleButton Grid.Row="7" Grid.Column="1" IsChecked="{Binding DebugBoundingBoxes}"/>
|
||||
|
||||
<Label Grid.Row="8" Grid.Column="0" Content="{DynamicResource Str_DebugPaths}"/>
|
||||
<ToggleButton Grid.Row="8" Grid.Column="1" IsChecked="{Binding DebugPaths}"/>
|
||||
|
||||
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource Str_DebugPoints}"/>
|
||||
<ToggleButton Grid.Row="9" Grid.Column="1" IsChecked="{Binding DebugPoints}"/>
|
||||
|
||||
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource Str_DebugClippings}"/>
|
||||
<ToggleButton Grid.Row="10" Grid.Column="1" IsChecked="{Binding DebugClippings}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
39
SpineViewer/Views/PreferenceDialog.xaml.cs
Normal file
39
SpineViewer/Views/PreferenceDialog.xaml.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using SpineViewer.Services;
|
||||
using SpineViewer.ViewModels.Exporters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace SpineViewer.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// PreferenceDialog.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PreferenceDialog : Window
|
||||
{
|
||||
public PreferenceDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ButtonOK_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = true;
|
||||
}
|
||||
|
||||
private void ButtonCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user