Compare commits

..

15 Commits

Author SHA1 Message Date
ww-rm
b3cd0b9349 Merge pull request #99 from ww-rm/dev/wpf
v0.15.15
2025-09-11 23:20:45 +08:00
ww-rm
1c545b8c37 update to v0.15.15 2025-09-11 23:19:24 +08:00
ww-rm
d660dd1c4a update changelog 2025-09-11 23:19:18 +08:00
ww-rm
9c0acf7302 增加报错信息 2025-09-11 23:17:13 +08:00
ww-rm
415df555c7 增加导入后自动选中最后一项 2025-09-08 21:50:11 +08:00
ww-rm
5ef13239da Merge pull request #97 from ww-rm/dev/wpf
v0.15.14
2025-09-08 00:07:36 +08:00
ww-rm
13ef873650 update to v0.15.14 2025-09-08 00:05:58 +08:00
ww-rm
78b9834f6c update changelog 2025-09-08 00:05:34 +08:00
ww-rm
672a695b20 增加上一次状态的保存和恢复 2025-09-08 00:00:49 +08:00
ww-rm
e9951ed79a 增加日志版本号输出 2025-09-05 11:36:52 +08:00
ww-rm
0c16b2f104 Merge pull request #93 from ww-rm/dev/wpf
v0.15.13
2025-09-04 20:09:18 +08:00
ww-rm
7628075420 update to v0.15.13 2025-09-04 20:08:08 +08:00
ww-rm
6f896bdaad update changelog 2025-09-04 20:07:54 +08:00
ww-rm
98930db4b6 增加预览画面首选项 2025-09-04 20:07:35 +08:00
ww-rm
c7493372e9 增加布局存储和还原 2025-09-04 19:27:10 +08:00
23 changed files with 323 additions and 65 deletions

View File

@@ -1,5 +1,21 @@
# CHANGELOG
## v0.15.15
- 增加报错信息
- 导入后自动选中最后一项
## v0.15.14
- 将预览画面的首选项移动至上一次状态参数中
- 增加预览画面像素的自动保存和恢复
- 增加日志启动时的版本号输出
## v0.15.13
- 增加程序布局自动存储和还原
- 增加部分预览画面首选项
## v0.15.12
- 增加单个模型和单个轨道的时间因子

View File

@@ -30,8 +30,15 @@ namespace Spine.Implementations.SpineWrappers.V21
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -41,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V21
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -52,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V21
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -61,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V21
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,8 +30,15 @@ namespace Spine.Implementations.SpineWrappers.V34
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -41,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V34
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -52,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V34
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -61,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V34
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,8 +30,15 @@ namespace Spine.Implementations.SpineWrappers.V35
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -41,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V35
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -52,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V35
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -61,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V35
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,8 +30,15 @@ namespace Spine.Implementations.SpineWrappers.V36
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -41,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V36
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -52,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V36
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -61,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V36
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,8 +30,15 @@ namespace Spine.Implementations.SpineWrappers.V37
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -41,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V37
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -52,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V37
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -61,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V37
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -31,8 +31,15 @@ namespace Spine.Implementations.SpineWrappers.V38
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
try
{
@@ -42,8 +49,9 @@ namespace Spine.Implementations.SpineWrappers.V38
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -53,8 +61,9 @@ namespace Spine.Implementations.SpineWrappers.V38
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -62,7 +71,8 @@ namespace Spine.Implementations.SpineWrappers.V38
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,10 +30,16 @@ namespace Spine.Implementations.SpineWrappers.V40
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
// 加载 skel
try
{
if (Utf8Validator.IsUtf8(skelPath))
@@ -42,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V40
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -53,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V40
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -62,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V40
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,10 +30,16 @@ namespace Spine.Implementations.SpineWrappers.V41
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
// 加载 skel
try
{
if (Utf8Validator.IsUtf8(skelPath))
@@ -42,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V41
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -53,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V41
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -62,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V41
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -30,10 +30,16 @@ namespace Spine.Implementations.SpineWrappers.V42
: base(skelPath, atlasPath, textureLoader)
{
// 加载 atlas
try { _atlas = new Atlas(atlasPath, textureLoader); }
catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); }
try
{
_atlas = new Atlas(atlasPath, textureLoader);
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load atlas '{atlasPath}'");
}
// 加载 skel
try
{
if (Utf8Validator.IsUtf8(skelPath))
@@ -42,8 +48,9 @@ namespace Spine.Implementations.SpineWrappers.V42
{
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -53,8 +60,9 @@ namespace Spine.Implementations.SpineWrappers.V42
{
_skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath);
}
}
@@ -62,7 +70,8 @@ namespace Spine.Implementations.SpineWrappers.V42
catch (Exception ex)
{
_atlas.Dispose();
throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex);
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load skeleton file {skelPath}");
}
// 加载动画数据

View File

@@ -7,7 +7,7 @@
<TargetFramework>net8.0-windows</TargetFramework>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.15.12</Version>
<Version>0.15.15</Version>
</PropertyGroup>
<PropertyGroup>

View File

@@ -115,8 +115,9 @@ namespace Spine
{
_data = SpineObjectData.New(Version, skelPath, atlasPath, textureLoader);
}
catch
catch (Exception ex)
{
_logger.Trace(ex.ToString());
throw new InvalidDataException($"Failed to load spine with version '{version}'");
}
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NLog;
using Spine.SpineWrappers.Attachments;
namespace Spine.SpineWrappers
@@ -17,6 +18,8 @@ namespace Spine.SpineWrappers
ISpineObjectData,
IDisposable
{
protected static readonly Logger _logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// 构建版本对象
/// </summary>

View File

@@ -23,7 +23,7 @@ namespace SpineViewer
{
InitializeLogConfiguration();
_logger = LogManager.GetCurrentClassLogger();
_logger.Info("Application Started");
_logger.Info("Application Started, v{0}", Version);
AppDomain.CurrentDomain.UnhandledException += (s, e) =>
{

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
namespace SpineViewer.Models
{
public class LastStateModel
{
#region
public double WindowLeft { get; set; }
public double WindowTop { get; set; }
public double WindowWidth { get; set; }
public double WindowHeight { get; set; }
public WindowState WindowState { get; set; }
public double RootGridCol0Width { get; set; }
public double ModelListRow0Height { get; set; }
public double ExplorerGridRow0Height { get; set; }
public double RightPanelGridRow0Height { get; set; }
#endregion
#region
public uint ResolutionX { get; set; } = 1500;
public uint ResolutionY { get; set; } = 1000;
public uint MaxFps { get; set; } = 30;
public float Speed { get; set; } = 1f;
public bool ShowAxis { get; set; } = true;
public Color BackgroundColor { get; set; } = Color.FromRgb(105, 105, 105);
#endregion
}
}

View File

@@ -229,6 +229,8 @@
<s:String x:Key="Str_SpineLoadPreference">Model Loading Options</s:String>
<s:String x:Key="Str_RendererPreference">Preview Options</s:String>
<s:String x:Key="Str_AppPreference">Application Options</s:String>
<s:String x:Key="Str_Language">Language</s:String>

View File

@@ -229,6 +229,8 @@
<s:String x:Key="Str_SpineLoadPreference">モデル読み込みオプション</s:String>
<s:String x:Key="Str_RendererPreference">プレビュー画面オプション</s:String>
<s:String x:Key="Str_AppPreference">アプリケーションプション</s:String>
<s:String x:Key="Str_Language">言語</s:String>

View File

@@ -229,6 +229,8 @@
<s:String x:Key="Str_SpineLoadPreference">模型加载选项</s:String>
<s:String x:Key="Str_RendererPreference">预览画面选项</s:String>
<s:String x:Key="Str_AppPreference">应用程序选项</s:String>
<s:String x:Key="Str_Language">语言</s:String>

View File

@@ -7,7 +7,7 @@
<TargetFramework>net8.0-windows</TargetFramework>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.15.12</Version>
<Version>0.15.15</Version>
<OutputType>WinExe</OutputType>
<UseWPF>true</UseWPF>
</PropertyGroup>

View File

@@ -86,6 +86,14 @@ namespace SpineViewer.ViewModels.MainWindow
/// </summary>
public event NotifyCollectionChangedEventHandler? RequestSelectionChanging;
public void SetResolution(uint x, uint y)
{
var lastRes = _renderer.Resolution;
_renderer.Resolution = new(x, y);
if (lastRes.X != x) OnPropertyChanged(nameof(ResolutionX));
if (lastRes.Y != y) OnPropertyChanged(nameof(ResolutionY));
}
public uint ResolutionX
{
get => _renderer.Resolution.X;
@@ -455,8 +463,7 @@ namespace SpineViewer.ViewModels.MainWindow
}
set
{
ResolutionX = value.ResolutionX;
ResolutionY = value.ResolutionY;
SetResolution(value.ResolutionX, value.ResolutionY);
CenterX = value.CenterX;
CenterY = value.CenterY;
Zoom = value.Zoom;

View File

@@ -11,6 +11,7 @@ using SpineViewer.ViewModels.Exporters;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
@@ -45,6 +46,11 @@ namespace SpineViewer.ViewModels.MainWindow
_customFFmpegExporterViewModel = new(_vmMain);
}
/// <summary>
/// 请求选中项发生变化
/// </summary>
public event NotifyCollectionChangedEventHandler? RequestSelectionChanging;
/// <summary>
/// 单帧导出 ViewModel
/// </summary>
@@ -489,6 +495,19 @@ namespace SpineViewer.ViewModels.MainWindow
{
var sp = new SpineObjectModel(skelPath, atlasPath);
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
if (Application.Current.Dispatcher.CheckAccess())
{
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Reset));
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Add, sp));
}
else
{
Application.Current.Dispatcher.Invoke(() =>
{
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Reset));
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Add, sp));
});
}
return true;
}
catch (Exception ex)
@@ -505,6 +524,19 @@ namespace SpineViewer.ViewModels.MainWindow
{
var sp = new SpineObjectModel(cfg);
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
if (Application.Current.Dispatcher.CheckAccess())
{
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Reset));
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Add, sp));
}
else
{
Application.Current.Dispatcher.Invoke(() =>
{
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Reset));
RequestSelectionChanging?.Invoke(this, new(NotifyCollectionChangedAction.Add, sp));
});
}
return true;
}
catch (Exception ex)

View File

@@ -76,7 +76,7 @@
</Border>
<Border Grid.Row="1">
<Grid>
<Grid x:Name="_rootGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
@@ -91,7 +91,7 @@
<!-- 模型列表页 -->
<TabItem Header="{DynamicResource Str_SpineObject}">
<Grid>
<Grid x:Name="_modelListGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
@@ -578,7 +578,7 @@
<!-- 浏览页 -->
<TabItem Header="{DynamicResource Str_Explorer}" DataContext="{Binding ExplorerListViewModel}">
<Grid>
<Grid x:Name="_explorerGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
@@ -785,14 +785,14 @@
<GridSplitter Grid.Column="1" ResizeDirection="Columns"/>
<Border Grid.Column="2">
<Grid>
<Grid x:Name="_rightPanelGrid">
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>

View File

@@ -3,12 +3,15 @@ using NLog;
using NLog.Layouts;
using NLog.Targets;
using Spine;
using SpineViewer.Models;
using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Utils;
using SpineViewer.ViewModels.MainWindow;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
@@ -26,6 +29,11 @@ namespace SpineViewer.Views;
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// 上一次状态文件保存路径
/// </summary>
public static readonly string LastStateFilePath = Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "laststate.json");
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private ListViewItem? _listViewDragSourceItem = null;
private Point _listViewDragSourcePoint;
@@ -38,8 +46,8 @@ public partial class MainWindow : Window
InitializeLogConfiguration();
_vm = new (_renderPanel);
DataContext = _vm;
_vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
_vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
}
@@ -53,8 +61,7 @@ public partial class MainWindow : Window
_renderPanel.CanvasMouseButtonReleased += vm.CanvasMouseButtonReleased;
// 设置默认参数并启动渲染
vm.ResolutionX = 1500;
vm.ResolutionY = 1000;
vm.SetResolution(1500, 1000);
vm.Zoom = 0.75f;
vm.CenterX = 0;
vm.CenterY = 0;
@@ -64,10 +71,14 @@ public partial class MainWindow : Window
// 加载首选项
_vm.PreferenceViewModel.LoadPreference();
LoadLastState();
}
private void MainWindow_Closed(object? sender, EventArgs e)
{
SaveLastState();
var vm = _vm.SFMLRendererViewModel;
vm.StopRender();
}
@@ -100,6 +111,63 @@ public partial class MainWindow : Window
LogManager.ReconfigExistingLoggers();
}
private void LoadLastState()
{
if (JsonHelper.Deserialize<LastStateModel>(LastStateFilePath, out var m, true))
{
Left = m.WindowLeft;
Top = m.WindowTop;
Width = m.WindowWidth;
Height = m.WindowHeight;
if (m.WindowState == WindowState.Maximized)
{
WindowState = WindowState.Maximized;
}
else
{
WindowState = WindowState.Normal;
}
_rootGrid.ColumnDefinitions[0].Width = new(m.RootGridCol0Width);
_modelListGrid.RowDefinitions[0].Height = new(m.ModelListRow0Height);
_explorerGrid.RowDefinitions[0].Height = new(m.ExplorerGridRow0Height);
_rightPanelGrid.RowDefinitions[0].Height = new(m.RightPanelGridRow0Height);
_vm.SFMLRendererViewModel.SetResolution(m.ResolutionX, m.ResolutionY);
_vm.SFMLRendererViewModel.MaxFps = m.MaxFps;
_vm.SFMLRendererViewModel.Speed = m.Speed;
_vm.SFMLRendererViewModel.ShowAxis = m.ShowAxis;
_vm.SFMLRendererViewModel.BackgroundColor = m.BackgroundColor;
}
}
private void SaveLastState()
{
var m = new LastStateModel()
{
WindowLeft = Left,
WindowTop = Top,
WindowWidth = Width,
WindowHeight = Height,
WindowState = WindowState,
RootGridCol0Width = _rootGrid.ColumnDefinitions[0].ActualWidth,
ModelListRow0Height = _modelListGrid.RowDefinitions[0].ActualHeight,
ExplorerGridRow0Height = _explorerGrid.RowDefinitions[0].ActualHeight,
RightPanelGridRow0Height = _rightPanelGrid.RowDefinitions[0].ActualHeight,
ResolutionX = _vm.SFMLRendererViewModel.ResolutionX,
ResolutionY = _vm.SFMLRendererViewModel.ResolutionY,
MaxFps = _vm.SFMLRendererViewModel.MaxFps,
Speed = _vm.SFMLRendererViewModel.Speed,
ShowAxis = _vm.SFMLRendererViewModel.ShowAxis,
BackgroundColor = _vm.SFMLRendererViewModel.BackgroundColor,
};
JsonHelper.Serialize(m, LastStateFilePath);
}
#region _spinesListView
private void SpinesListView_RequestSelectionChanging(object? sender, NotifyCollectionChangedEventArgs e)
@@ -236,9 +304,7 @@ public partial class MainWindow : Window
IntPtr hwnd = new WindowInteropHelper(this).Handle;
if (Win32.GetScreenResolution(hwnd, out var resX, out var resY))
{
var vm = _vm.SFMLRendererViewModel;
vm.ResolutionX = resX;
vm.ResolutionY = resY;
_vm.SFMLRendererViewModel.SetResolution(resX, resY);
}
HandyControl.Controls.IconElement.SetGeometry(_fullScreenButton, AppResource.Geo_ArrowsMinimize);