增加语言设置
This commit is contained in:
@@ -21,7 +21,6 @@ namespace Spine
|
|||||||
{
|
{
|
||||||
[".skel"] = ".atlas",
|
[".skel"] = ".atlas",
|
||||||
[".json"] = ".atlas",
|
[".json"] = ".atlas",
|
||||||
[".skel.bytes"] = ".atlas.bytes",
|
|
||||||
}.ToFrozenDictionary();
|
}.ToFrozenDictionary();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
|
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
|
||||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
|
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
|
||||||
<ResourceDictionary Source="/Resources/Geometries.xaml"/>
|
<ResourceDictionary Source="/Resources/Geometries.xaml"/>
|
||||||
<ResourceDictionary Source="/Resources/Strings/zh-cn.xaml"/>
|
<ResourceDictionary Source="/Resources/Strings/zh.xaml"/>
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<Style x:Key="MyToggleButton" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ToggleButtonSwitch}">
|
<Style x:Key="MyToggleButton" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ToggleButtonSwitch}">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using SpineViewer.Views;
|
using SpineViewer.Views;
|
||||||
|
using System.Collections.Frozen;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -7,86 +8,108 @@ using System.Globalization;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace SpineViewer;
|
namespace SpineViewer
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for App.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
{
|
||||||
public static string Version => Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
private static readonly Logger _logger;
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
static App()
|
|
||||||
{
|
{
|
||||||
InitializeLogConfiguration();
|
public static string Version => Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
|
||||||
_logger = LogManager.GetCurrentClassLogger();
|
|
||||||
_logger.Info("Application Started");
|
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
|
private static readonly Logger _logger;
|
||||||
|
|
||||||
|
static App()
|
||||||
{
|
{
|
||||||
_logger.Fatal("Unhandled exception: {0}", e.ExceptionObject);
|
InitializeLogConfiguration();
|
||||||
};
|
_logger = LogManager.GetCurrentClassLogger();
|
||||||
TaskScheduler.UnobservedTaskException += (s, e) =>
|
_logger.Info("Application Started");
|
||||||
|
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
|
||||||
|
{
|
||||||
|
_logger.Fatal("Unhandled exception: {0}", e.ExceptionObject);
|
||||||
|
};
|
||||||
|
TaskScheduler.UnobservedTaskException += (s, e) =>
|
||||||
|
{
|
||||||
|
_logger.Trace(e.Exception.ToString());
|
||||||
|
_logger.Error("Unobserved task exception: {0}", e.Exception.Message);
|
||||||
|
e.SetObserved();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InitializeLogConfiguration()
|
||||||
|
{
|
||||||
|
var config = new NLog.Config.LoggingConfiguration();
|
||||||
|
|
||||||
|
// 文件日志
|
||||||
|
var fileTarget = new NLog.Targets.FileTarget("fileTarget")
|
||||||
|
{
|
||||||
|
Encoding = System.Text.Encoding.UTF8,
|
||||||
|
FileName = "${basedir}/logs/app.log",
|
||||||
|
ArchiveFileName = "${basedir}/logs/app.{#}.log",
|
||||||
|
ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.Rolling,
|
||||||
|
ArchiveAboveSize = 1048576,
|
||||||
|
MaxArchiveFiles = 5,
|
||||||
|
Layout = "${date:format=yyyy-MM-dd HH\\:mm\\:ss} - ${level:uppercase=true} - ${callsite-filename:includeSourcePath=false}:${callsite-linenumber} - ${message}"
|
||||||
|
};
|
||||||
|
|
||||||
|
config.AddTarget(fileTarget);
|
||||||
|
config.AddRule(LogLevel.Trace, LogLevel.Fatal, fileTarget);
|
||||||
|
LogManager.Configuration = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnStartup(e);
|
||||||
|
|
||||||
|
var dict = new ResourceDictionary();
|
||||||
|
|
||||||
|
var uiCulture = CultureInfo.CurrentUICulture.Name.ToLowerInvariant();
|
||||||
|
_logger.Info("Current UI Culture: {0}", uiCulture);
|
||||||
|
|
||||||
|
if (uiCulture.StartsWith("zh")) { } // 默认就是中文, 无需操作
|
||||||
|
else if (uiCulture.StartsWith("ja")) Language = AppLanguage.JA;
|
||||||
|
else Language = AppLanguage.EN;
|
||||||
|
|
||||||
|
Resources.MergedDictionaries.Add(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
_logger.Trace(e.Exception.ToString());
|
_logger.Trace(e.Exception.ToString());
|
||||||
_logger.Error("Unobserved task exception: {0}", e.Exception.Message);
|
_logger.Error("Dispatcher unhandled exception: {0}", e.Exception.Message);
|
||||||
e.SetObserved();
|
e.Handled = true;
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void InitializeLogConfiguration()
|
|
||||||
{
|
|
||||||
var config = new NLog.Config.LoggingConfiguration();
|
|
||||||
|
|
||||||
// 文件日志
|
|
||||||
var fileTarget = new NLog.Targets.FileTarget("fileTarget")
|
|
||||||
{
|
|
||||||
Encoding = System.Text.Encoding.UTF8,
|
|
||||||
FileName = "${basedir}/logs/app.log",
|
|
||||||
ArchiveFileName = "${basedir}/logs/app.{#}.log",
|
|
||||||
ArchiveNumbering = NLog.Targets.ArchiveNumberingMode.Rolling,
|
|
||||||
ArchiveAboveSize = 1048576,
|
|
||||||
MaxArchiveFiles = 5,
|
|
||||||
Layout = "${date:format=yyyy-MM-dd HH\\:mm\\:ss} - ${level:uppercase=true} - ${callsite-filename:includeSourcePath=false}:${callsite-linenumber} - ${message}"
|
|
||||||
};
|
|
||||||
|
|
||||||
config.AddTarget(fileTarget);
|
|
||||||
config.AddRule(LogLevel.Trace, LogLevel.Fatal, fileTarget);
|
|
||||||
LogManager.Configuration = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnStartup(e);
|
|
||||||
|
|
||||||
var dict = new ResourceDictionary();
|
|
||||||
|
|
||||||
var uiCulture = CultureInfo.CurrentUICulture.Name.ToLowerInvariant();
|
|
||||||
_logger.Info("Current UI Culture: {0}", uiCulture);
|
|
||||||
|
|
||||||
if (uiCulture.StartsWith("zh"))
|
|
||||||
{
|
|
||||||
; // 默认就是中文, 无需操作
|
|
||||||
}
|
|
||||||
else if (uiCulture.StartsWith("ja"))
|
|
||||||
{
|
|
||||||
dict.Source = new("Resources/Strings/ja-jp.xaml", UriKind.Relative);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dict.Source = new("Resources/Strings/en-us.xaml", UriKind.Relative);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Resources.MergedDictionaries.Add(dict);
|
/// <summary>
|
||||||
|
/// 程序语言
|
||||||
|
/// </summary>
|
||||||
|
public AppLanguage Language
|
||||||
|
{
|
||||||
|
get => _language;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var uri = $"Resources/Strings/{value.ToString().ToLower()}.xaml";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) });
|
||||||
|
_language = value;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
|
||||||
|
_logger.Trace(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private AppLanguage _language = AppLanguage.ZH;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
|
public enum AppLanguage
|
||||||
{
|
{
|
||||||
_logger.Trace(e.Exception.ToString());
|
ZH,
|
||||||
_logger.Error("Dispatcher unhandled exception: {0}", e.Exception.Message);
|
EN,
|
||||||
e.Handled = true;
|
JA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ namespace SpineViewer.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class PreferenceModel : ObservableObject
|
public partial class PreferenceModel : ObservableObject
|
||||||
{
|
{
|
||||||
|
|
||||||
#region 纹理加载首选项
|
#region 纹理加载首选项
|
||||||
|
|
||||||
[ObservableProperty]
|
[ObservableProperty]
|
||||||
@@ -67,6 +68,13 @@ namespace SpineViewer.Models
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 程序选项
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AppLanguage _appLanguage;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 序列化与反序列
|
#region 序列化与反序列
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -205,4 +205,7 @@
|
|||||||
|
|
||||||
<s:String x:Key="Str_SpineLoadPreference">Model Loading Options</s:String>
|
<s:String x:Key="Str_SpineLoadPreference">Model Loading Options</s:String>
|
||||||
|
|
||||||
|
<s:String x:Key="Str_AppPreference">Application Options</s:String>
|
||||||
|
<s:String x:Key="Str_Language">Language</s:String>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -205,5 +205,8 @@
|
|||||||
|
|
||||||
<s:String x:Key="Str_SpineLoadPreference">モデル読み込みオプション</s:String>
|
<s:String x:Key="Str_SpineLoadPreference">モデル読み込みオプション</s:String>
|
||||||
|
|
||||||
|
<s:String x:Key="Str_AppPreference">アプリケーションプション</s:String>
|
||||||
|
<s:String x:Key="Str_Language">言語</s:String>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
||||||
@@ -205,4 +205,7 @@
|
|||||||
|
|
||||||
<s:String x:Key="Str_SpineLoadPreference">模型加载选项</s:String>
|
<s:String x:Key="Str_SpineLoadPreference">模型加载选项</s:String>
|
||||||
|
|
||||||
|
<s:String x:Key="Str_AppPreference">应用程序选项</s:String>
|
||||||
|
<s:String x:Key="Str_Language">语言</s:String>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
@@ -18,7 +18,7 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
{
|
{
|
||||||
public class FFmpegVideoExporterViewModel(MainWindowViewModel vmMain) : VideoExporterViewModel(vmMain)
|
public class FFmpegVideoExporterViewModel(MainWindowViewModel vmMain) : VideoExporterViewModel(vmMain)
|
||||||
{
|
{
|
||||||
public ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormats { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray();
|
public ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormatOptions { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray();
|
||||||
|
|
||||||
public FFmpegVideoExporter.VideoFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
public FFmpegVideoExporter.VideoFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
||||||
protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4;
|
protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace SpineViewer.ViewModels.Exporters
|
|||||||
{
|
{
|
||||||
public class FrameExporterViewModel(MainWindowViewModel vmMain) : BaseExporterViewModel(vmMain)
|
public class FrameExporterViewModel(MainWindowViewModel vmMain) : BaseExporterViewModel(vmMain)
|
||||||
{
|
{
|
||||||
public ImmutableArray<SKEncodedImageFormat> FrameFormats { get; } = Enum.GetValues<SKEncodedImageFormat>().ToImmutableArray();
|
public ImmutableArray<SKEncodedImageFormat> FrameFormatOptions { get; } = Enum.GetValues<SKEncodedImageFormat>().ToImmutableArray();
|
||||||
|
|
||||||
public SKEncodedImageFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
public SKEncodedImageFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
||||||
protected SKEncodedImageFormat _format = SKEncodedImageFormat.Png;
|
protected SKEncodedImageFormat _format = SKEncodedImageFormat.Png;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using SpineViewer.Models;
|
|||||||
using SpineViewer.Services;
|
using SpineViewer.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -105,7 +106,8 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
DebugBoundingBoxes = DebugBoundingBoxes,
|
DebugBoundingBoxes = DebugBoundingBoxes,
|
||||||
DebugPaths = DebugPaths,
|
DebugPaths = DebugPaths,
|
||||||
DebugPoints = DebugPoints,
|
DebugPoints = DebugPoints,
|
||||||
DebugClippings = DebugClippings
|
DebugClippings = DebugClippings,
|
||||||
|
AppLanguage = AppLanguage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@@ -124,6 +126,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
DebugPaths = value.DebugPaths;
|
DebugPaths = value.DebugPaths;
|
||||||
DebugPoints = value.DebugPoints;
|
DebugPoints = value.DebugPoints;
|
||||||
DebugClippings = value.DebugClippings;
|
DebugClippings = value.DebugClippings;
|
||||||
|
AppLanguage = value.AppLanguage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,42 +152,88 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// TODO: 是否自动记忆模型参数
|
|
||||||
|
|
||||||
#region 模型加载首选项
|
#region 模型加载首选项
|
||||||
|
|
||||||
public bool UsePma { get => _usePma; set => SetProperty(ref _usePma, value); }
|
// TODO: 是否自动记忆模型参数
|
||||||
private bool _usePma;
|
|
||||||
|
|
||||||
public bool DebugTexture { get => _debugTexture; set => SetProperty(ref _debugTexture, value); }
|
public bool UsePma
|
||||||
private bool _debugTexture = true;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.UsePma;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.UsePma, value, v => SpineObjectListViewModel.LoadOptions.UsePma = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugBounds { get => _debugBounds; set => SetProperty(ref _debugBounds, value); }
|
public bool DebugTexture
|
||||||
private bool _debugBounds;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugTexture;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugTexture, value, v => SpineObjectListViewModel.LoadOptions.DebugTexture = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugBones { get => _debugBones; set => SetProperty(ref _debugBones, value); }
|
public bool DebugBounds
|
||||||
private bool _debugBones;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugBounds;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBounds, value, v => SpineObjectListViewModel.LoadOptions.DebugBounds = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugRegions { get => _debugRegions; set => SetProperty(ref _debugRegions, value); }
|
public bool DebugBones
|
||||||
private bool _debugRegions;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugBones;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBones, value, v => SpineObjectListViewModel.LoadOptions.DebugBones = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugMeshHulls { get => _debugMeshHulls; set => SetProperty(ref _debugMeshHulls, value); }
|
public bool DebugRegions
|
||||||
private bool _debugMeshHulls;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugRegions;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugRegions, value, v => SpineObjectListViewModel.LoadOptions.DebugRegions = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugMeshes { get => _debugMeshes; set => SetProperty(ref _debugMeshes, value); }
|
public bool DebugMeshHulls
|
||||||
private bool _debugMeshes;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugMeshHulls;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugMeshHulls, value, v => SpineObjectListViewModel.LoadOptions.DebugMeshHulls = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugBoundingBoxes { get => _debugBoundingBoxes; set => SetProperty(ref _debugBoundingBoxes, value); }
|
public bool DebugMeshes
|
||||||
private bool _debugBoundingBoxes;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugMeshes;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugMeshes, value, v => SpineObjectListViewModel.LoadOptions.DebugMeshes = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugPaths { get => _debugPaths; set => SetProperty(ref _debugPaths, value); }
|
public bool DebugBoundingBoxes
|
||||||
private bool _debugPaths;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes, value, v => SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugPoints { get => _debugPoints; set => SetProperty(ref _debugPoints, value); }
|
public bool DebugPaths
|
||||||
private bool _debugPoints;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugPaths;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugPaths, value, v => SpineObjectListViewModel.LoadOptions.DebugPaths = v);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DebugClippings { get => _debugClippings; set => SetProperty(ref _debugClippings, value); }
|
public bool DebugPoints
|
||||||
private bool _debugClippings;
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugPoints;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugPoints, value, v => SpineObjectListViewModel.LoadOptions.DebugPoints = v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DebugClippings
|
||||||
|
{
|
||||||
|
get => SpineObjectListViewModel.LoadOptions.DebugClippings;
|
||||||
|
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugClippings, value, v => SpineObjectListViewModel.LoadOptions.DebugClippings = v);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 程序选项
|
||||||
|
|
||||||
|
public static ImmutableArray<AppLanguage> AppLanguageOptions { get; } = Enum.GetValues<AppLanguage>().ToImmutableArray();
|
||||||
|
|
||||||
|
public AppLanguage AppLanguage
|
||||||
|
{
|
||||||
|
get => ((App)App.Current).Language;
|
||||||
|
set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
{
|
{
|
||||||
public class SpineObjectListViewModel : ObservableObject
|
public class SpineObjectListViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 加载选项
|
||||||
|
/// </summary>
|
||||||
|
public static SpineLoadOptions LoadOptions => _loadOptions;
|
||||||
|
private static readonly SpineLoadOptions _loadOptions = new();
|
||||||
|
|
||||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -249,41 +255,6 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
return true;
|
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>
|
||||||
/// 从路径列表添加对象
|
/// 从路径列表添加对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -369,5 +340,54 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
|
|
||||||
_logger.LogCurrentProcessMemoryUsage();
|
_logger.LogCurrentProcessMemoryUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 安全地在末尾添加一个模型, 发生错误会输出日志
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>是否添加成功</returns>
|
||||||
|
public bool AddSpineObject(string skelPath, string? atlasPath = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sp = new SpineObjectModel(skelPath, atlasPath)
|
||||||
|
{
|
||||||
|
UsePma = _loadOptions.UsePma,
|
||||||
|
DebugTexture = _loadOptions.DebugTexture,
|
||||||
|
DebugBounds = _loadOptions.DebugBounds,
|
||||||
|
DebugRegions = _loadOptions.DebugRegions,
|
||||||
|
DebugMeshHulls = _loadOptions.DebugMeshHulls,
|
||||||
|
DebugMeshes = _loadOptions.DebugMeshes,
|
||||||
|
DebugBoundingBoxes = _loadOptions.DebugBoundingBoxes,
|
||||||
|
DebugPaths = _loadOptions.DebugPaths,
|
||||||
|
DebugPoints = _loadOptions.DebugPoints,
|
||||||
|
DebugClippings = _loadOptions.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpineLoadOptions
|
||||||
|
{
|
||||||
|
// TODO: 判断是否记忆参数
|
||||||
|
public bool UsePma { get; set; }
|
||||||
|
public bool DebugTexture { get; set; } = true;
|
||||||
|
public bool DebugBounds { get; set; }
|
||||||
|
public bool DebugBones { get; set; }
|
||||||
|
public bool DebugRegions { get; set; }
|
||||||
|
public bool DebugMeshHulls { get; set; }
|
||||||
|
public bool DebugMeshes { get; set; }
|
||||||
|
public bool DebugBoundingBoxes { get; set; }
|
||||||
|
public bool DebugPaths { get; set; }
|
||||||
|
public bool DebugPoints { get; set; }
|
||||||
|
public bool DebugClippings { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<!-- 视频格式 -->
|
<!-- 视频格式 -->
|
||||||
<Label Grid.Row="13" Grid.Column="0" Content="{DynamicResource Str_VideoFormat}"/>
|
<Label Grid.Row="13" Grid.Column="0" Content="{DynamicResource Str_VideoFormat}"/>
|
||||||
<ComboBox Grid.Row="13" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding VideoFormats}"/>
|
<ComboBox Grid.Row="13" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding VideoFormatOptions}"/>
|
||||||
|
|
||||||
<!-- 动图是否循环 -->
|
<!-- 动图是否循环 -->
|
||||||
<Label Grid.Row="14" Grid.Column="0" Content="{DynamicResource Str_LoopPlay}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/>
|
<Label Grid.Row="14" Grid.Column="0" Content="{DynamicResource Str_LoopPlay}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/>
|
||||||
|
|||||||
@@ -110,7 +110,7 @@
|
|||||||
|
|
||||||
<!-- 图像格式 -->
|
<!-- 图像格式 -->
|
||||||
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource Str_ImageFormat}"/>
|
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource Str_ImageFormat}"/>
|
||||||
<ComboBox Grid.Row="9" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding FrameFormats}"/>
|
<ComboBox Grid.Row="9" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding FrameFormatOptions}"/>
|
||||||
|
|
||||||
<!-- 图像质量 -->
|
<!-- 图像质量 -->
|
||||||
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource Str_ImageQuality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/>
|
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource Str_ImageQuality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
<Window xmlns:hc="https://handyorg.github.io/handycontrol" x:Class="SpineViewer.Views.PreferenceDialog"
|
<Window x:Class="SpineViewer.Views.PreferenceDialog"
|
||||||
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:SpineViewer.Views"
|
xmlns:local="clr-namespace:SpineViewer.Views"
|
||||||
xmlns:models="clr-namespace:SpineViewer.Models"
|
xmlns:models="clr-namespace:SpineViewer.Models"
|
||||||
|
xmlns:vm="clr-namespace:SpineViewer.ViewModels.MainWindow"
|
||||||
d:DataContext="{d:DesignInstance Type=models:PreferenceModel}"
|
d:DataContext="{d:DesignInstance Type=models:PreferenceModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="{DynamicResource Str_Preference}"
|
Title="{DynamicResource Str_Preference}"
|
||||||
@@ -125,6 +127,24 @@
|
|||||||
<ToggleButton Grid.Row="10" Grid.Column="1" IsChecked="{Binding DebugClippings}"/>
|
<ToggleButton Grid.Row="10" Grid.Column="1" IsChecked="{Binding DebugClippings}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Header="{DynamicResource Str_AppPreference}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_Language}"/>
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||||
|
SelectedItem="{Binding AppLanguage}"
|
||||||
|
ItemsSource="{x:Static vm:PreferenceViewModel.AppLanguageOptions}"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
Reference in New Issue
Block a user