diff --git a/SpineViewer/Models/PreferenceModel.cs b/SpineViewer/Models/PreferenceModel.cs
index da94a82..635ec10 100644
--- a/SpineViewer/Models/PreferenceModel.cs
+++ b/SpineViewer/Models/PreferenceModel.cs
@@ -73,6 +73,9 @@ namespace SpineViewer.Models
#region 程序选项
+ [ObservableProperty]
+ private bool _wallpaperView;
+
[ObservableProperty]
private bool _renderSelectedOnly;
diff --git a/SpineViewer/Resources/Strings/en.xaml b/SpineViewer/Resources/Strings/en.xaml
index 7cdda02..9d7a0d5 100644
--- a/SpineViewer/Resources/Strings/en.xaml
+++ b/SpineViewer/Resources/Strings/en.xaml
@@ -118,6 +118,7 @@
Max FPS
Maximum frame rate of the preview. Set to 0 for no limit.
Playback Speed
+ Wallpaper View
Render Selected Only
Show Axis
Background Color
diff --git a/SpineViewer/Resources/Strings/ja.xaml b/SpineViewer/Resources/Strings/ja.xaml
index 5f4ef84..e1fb869 100644
--- a/SpineViewer/Resources/Strings/ja.xaml
+++ b/SpineViewer/Resources/Strings/ja.xaml
@@ -118,6 +118,7 @@
最大FPS
プレビュー画面の最大フレームレート。0 に設定すると制限なし。
再生速度
+ 壁紙表示
選択のみレンダリング
座標軸を表示
背景色
diff --git a/SpineViewer/Resources/Strings/zh.xaml b/SpineViewer/Resources/Strings/zh.xaml
index 793fd7e..05f485d 100644
--- a/SpineViewer/Resources/Strings/zh.xaml
+++ b/SpineViewer/Resources/Strings/zh.xaml
@@ -118,6 +118,7 @@
最大帧率
预览画面的最大帧率,设置为 0 时则无帧率限制
播放速度
+ 桌面投影
仅渲染选中
显示坐标轴
背景颜色
diff --git a/SpineViewer/ViewModels/MainWindow/MainWindowViewModel.cs b/SpineViewer/ViewModels/MainWindow/MainWindowViewModel.cs
index 656f36c..044e33a 100644
--- a/SpineViewer/ViewModels/MainWindow/MainWindowViewModel.cs
+++ b/SpineViewer/ViewModels/MainWindow/MainWindowViewModel.cs
@@ -77,7 +77,15 @@ namespace SpineViewer.ViewModels.MainWindow
public SFMLRendererViewModel SFMLRendererViewModel => _sfmlRendererViewModel;
private readonly SFMLRendererViewModel _sfmlRendererViewModel;
- public RelayCommand Cmd_Exit => new(App.Current.Shutdown);
+ public RelayCommand Cmd_SwitchWallpaperView => _cmd_SwitchWallpaperView ??= new(() =>
+ {
+ _preferenceViewModel.WallpaperView = !_preferenceViewModel.WallpaperView;
+ _preferenceViewModel.SavePreference();
+ });
+ private RelayCommand _cmd_SwitchWallpaperView;
+
+ public RelayCommand Cmd_Exit => _cmd_Exit ??= new(App.Current.Shutdown);
+ private RelayCommand? _cmd_Exit;
///
/// 打开工作区
@@ -137,5 +145,6 @@ namespace SpineViewer.ViewModels.MainWindow
_spineObjectListViewModel.LoadedSpineObjects = value.LoadedSpineObjects;
}
}
+
}
}
\ No newline at end of file
diff --git a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
index a5e3adc..bcdefb7 100644
--- a/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
+++ b/SpineViewer/ViewModels/MainWindow/PreferenceViewModel.cs
@@ -111,6 +111,7 @@ namespace SpineViewer.ViewModels.MainWindow
DebugPoints = DebugPoints,
DebugClippings = DebugClippings,
+ WallpaperView = WallpaperView,
RenderSelectedOnly = RenderSelectedOnly,
AssociateFileSuffix = AssociateFileSuffix,
AppLanguage = AppLanguage,
@@ -136,6 +137,7 @@ namespace SpineViewer.ViewModels.MainWindow
DebugPoints = value.DebugPoints;
DebugClippings = value.DebugClippings;
+ WallpaperView = value.WallpaperView;
RenderSelectedOnly = value.RenderSelectedOnly;
AssociateFileSuffix = value.AssociateFileSuffix;
AppLanguage = value.AppLanguage;
@@ -244,6 +246,19 @@ namespace SpineViewer.ViewModels.MainWindow
public static ImmutableArray AppLanguageOptions { get; } = Enum.GetValues().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;
diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml
index d6d2e6d..ffde3f7 100644
--- a/SpineViewer/Views/MainWindow.xaml
+++ b/SpineViewer/Views/MainWindow.xaml
@@ -940,7 +940,7 @@
MouseDoubleClick="_notifyIcon_MouseDoubleClick">
-
+
diff --git a/SpineViewer/Views/MainWindow.xaml.cs b/SpineViewer/Views/MainWindow.xaml.cs
index b65e3cf..65e2b60 100644
--- a/SpineViewer/Views/MainWindow.xaml.cs
+++ b/SpineViewer/Views/MainWindow.xaml.cs
@@ -12,6 +12,7 @@ using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using System.Reflection.Metadata;
using System.Text;
using System.Windows;
using System.Windows.Controls;
@@ -47,67 +48,28 @@ public partial class MainWindow : Window
InitializeComponent();
InitializeLogConfiguration();
- _wallpaperRenderWindow = new(new(500, 500), "SpineViewerWallpaper", SFML.Window.Styles.None);
+ // Initialize Wallpaper RenderWindow
+ _wallpaperRenderWindow = new(new(1, 1), "SpineViewerWallpaper", SFML.Window.Styles.None);
_wallpaperRenderWindow.SetVisible(false);
+ var handle = _wallpaperRenderWindow.SystemHandle;
+ var style = User32.GetWindowLong(handle, User32.GWL_STYLE) | User32.WS_POPUP;
+ var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED | User32.WS_EX_TOOLWINDOW;
+ User32.SetWindowLong(handle, User32.GWL_STYLE, style);
+ User32.SetWindowLong(handle, User32.GWL_EXSTYLE, exStyle);
+ User32.SetLayeredWindowAttributes(handle, 0, byte.MaxValue, User32.LWA_ALPHA);
+
DataContext = _vm = new(_renderPanel, _wallpaperRenderWindow);
// XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定
_notifyIcon.Text = _vm.Title;
- _vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
- _vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
Loaded += MainWindow_Loaded;
ContentRendered += MainWindow_ContentRendered;
Closed += MainWindow_Closed;
- }
- private void MainWindow_Loaded(object sender, RoutedEventArgs e)
- {
- var vm = _vm.SFMLRendererViewModel;
- _renderPanel.CanvasMouseWheelScrolled += vm.CanvasMouseWheelScrolled;
- _renderPanel.CanvasMouseButtonPressed += (s, e) => { vm.CanvasMouseButtonPressed(s, e); _spinesListView.Focus(); }; // 用户点击画布后强制转移焦点至列表
- _renderPanel.CanvasMouseMove += vm.CanvasMouseMove;
- _renderPanel.CanvasMouseButtonReleased += vm.CanvasMouseButtonReleased;
-
- // 设置默认参数并启动渲染
- vm.SetResolution(1500, 1000);
- vm.Zoom = 0.75f;
- vm.CenterX = 0;
- vm.CenterY = 0;
- vm.FlipY = true;
- vm.MaxFps = 30;
- vm.StartRender();
-
- // 加载首选项
- _vm.PreferenceViewModel.LoadPreference();
-
- LoadLastState();
- }
-
- private void MainWindow_ContentRendered(object? sender, EventArgs e)
- {
- string[] args = Environment.GetCommandLineArgs();
- if (args.Length > 1)
- {
- string[] filePaths = args.Skip(1).ToArray();
- _vm.SpineObjectListViewModel.AddSpineObjectFromFileList(filePaths);
- }
- }
-
- private void MainWindow_Closed(object? sender, EventArgs e)
- {
- SaveLastState();
-
- var vm = _vm.SFMLRendererViewModel;
- vm.StopRender();
- }
-
- ///
- /// 给管道通信提供的打开文件外部调用方法
- ///
- public void OpenFiles(IEnumerable filePaths)
- {
- _vm.SpineObjectListViewModel.AddSpineObjectFromFileList(filePaths);
+ _vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
+ _vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
+ _vm.PreferenceViewModel.PropertyChanged += PreferenceViewModel_PropertyChanged;
}
///
@@ -195,6 +157,95 @@ public partial class MainWindow : Window
JsonHelper.Serialize(m, LastStateFilePath);
}
+ ///
+ /// 给管道通信提供的打开文件外部调用方法
+ ///
+ public void OpenFiles(IEnumerable filePaths)
+ {
+ _vm.SpineObjectListViewModel.AddSpineObjectFromFileList(filePaths);
+ }
+
+ #region MainWindow 事件处理
+
+ private void MainWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+ var vm = _vm.SFMLRendererViewModel;
+ _renderPanel.CanvasMouseWheelScrolled += vm.CanvasMouseWheelScrolled;
+ _renderPanel.CanvasMouseButtonPressed += (s, e) => { vm.CanvasMouseButtonPressed(s, e); _spinesListView.Focus(); }; // 用户点击画布后强制转移焦点至列表
+ _renderPanel.CanvasMouseMove += vm.CanvasMouseMove;
+ _renderPanel.CanvasMouseButtonReleased += vm.CanvasMouseButtonReleased;
+
+ // 设置默认参数并启动渲染
+ vm.SetResolution(1500, 1000);
+ vm.Zoom = 0.75f;
+ vm.CenterX = 0;
+ vm.CenterY = 0;
+ vm.FlipY = true;
+ vm.MaxFps = 30;
+ vm.StartRender();
+
+ // 加载首选项
+ _vm.PreferenceViewModel.LoadPreference();
+
+ LoadLastState();
+ }
+
+ private void MainWindow_ContentRendered(object? sender, EventArgs e)
+ {
+ string[] args = Environment.GetCommandLineArgs();
+ if (args.Length > 1)
+ {
+ string[] filePaths = args.Skip(1).ToArray();
+ _vm.SpineObjectListViewModel.AddSpineObjectFromFileList(filePaths);
+ }
+ }
+
+ private void MainWindow_Closed(object? sender, EventArgs e)
+ {
+ SaveLastState();
+
+ var vm = _vm.SFMLRendererViewModel;
+ vm.StopRender();
+ }
+
+ #endregion
+
+ #region PreferenceViewModel 事件处理
+
+ private void PreferenceViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(PreferenceViewModel.WallpaperView))
+ {
+ if (_vm.PreferenceViewModel.WallpaperView)
+ {
+ var workerw = User32.GetWorkerW();
+ if (workerw == IntPtr.Zero)
+ {
+ _logger.Error("Failed to enable wallpaper view, WorkerW not found");
+ return;
+ }
+ var wnd = _wallpaperRenderWindow;
+ var handle = wnd.SystemHandle;
+
+ User32.GetPrimaryScreenResolution(out var sw, out var sh);
+
+ User32.SetParent(handle, workerw);
+ User32.SetLayeredWindowAttributes(handle, 0, byte.MaxValue, User32.LWA_ALPHA);
+
+ wnd.Position = new(0, 0);
+ wnd.Size = new(sw + 1, sh);
+ wnd.Size = new(sw, sh);
+ wnd.SetVisible(true);
+ }
+ else
+ {
+ _wallpaperRenderWindow.SetVisible(false);
+ }
+ }
+ }
+
+ #endregion
+
#region _spinesListView 事件处理
private void SpinesListView_RequestSelectionChanging(object? sender, NotifyCollectionChangedEventArgs e)
@@ -609,29 +660,7 @@ public partial class MainWindow : Window
private void DebugMenuItem_Click(object sender, RoutedEventArgs e)
{
#if DEBUG
- var www = _wallpaperRenderWindow;
- User32.GetPrimaryScreenResolution(out var sw, out var sh);
- www.Position = new(0, 0);
- www.Size = new(sw, sh);
- var handle = www.SystemHandle;
- Debug.WriteLine($"Handle: {handle:x8}");
-
- var style = User32.GetWindowLong(handle, User32.GWL_STYLE) | User32.WS_POPUP;
- var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED | User32.WS_EX_TOOLWINDOW | User32.WS_EX_TOPMOST;
- User32.SetWindowLong(handle, User32.GWL_STYLE, style);
- User32.SetWindowLong(handle, User32.GWL_EXSTYLE, exStyle);
- User32.SetLayeredWindowAttributes(handle, 0, 200, User32.LWA_ALPHA);
-
- var workerw = User32.GetWorkerW();
- var res = User32.SetParent(handle, workerw);
- Debug.WriteLine($"SetParent: {res:x8}");
-
- User32.SetLayeredWindowAttributes(handle, 0, 255, User32.LWA_ALPHA);
- var s = www.Size;
- www.Size = new(s.X + 1, s.Y + 1);
- www.Size = s;
- www.SetVisible(true);
#endif
}
}
\ No newline at end of file
diff --git a/SpineViewer/Views/PreferenceDialog.xaml b/SpineViewer/Views/PreferenceDialog.xaml
index 37723e4..644cf8a 100644
--- a/SpineViewer/Views/PreferenceDialog.xaml
+++ b/SpineViewer/Views/PreferenceDialog.xaml
@@ -144,16 +144,20 @@
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+