From 7bd3e3669ba9ca733ed70ddc8f69091c5b0723f7 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Sun, 15 Jun 2025 14:38:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Models/SpineObjectConfigModel.cs | 2 + SpineViewer/Models/SpineObjectModel.cs | 4 ++ SpineViewer/Services/DialogService.cs | 46 +++++++++---- .../MainWindow/SpineObjectListViewModel.cs | 69 ++++++++++++++++++- SpineViewer/Views/MainWindow.xaml | 9 ++- 5 files changed, 113 insertions(+), 17 deletions(-) diff --git a/SpineViewer/Models/SpineObjectConfigModel.cs b/SpineViewer/Models/SpineObjectConfigModel.cs index bf83ac7..b776704 100644 --- a/SpineViewer/Models/SpineObjectConfigModel.cs +++ b/SpineViewer/Models/SpineObjectConfigModel.cs @@ -13,6 +13,8 @@ namespace SpineViewer.Models { public class SpineObjectConfigModel { + public bool IsShown { get; set; } = true; + public bool UsePma { get; set; } public string Physics { get; set; } = ISkeleton.Physics.Update.ToString(); diff --git a/SpineViewer/Models/SpineObjectModel.cs b/SpineViewer/Models/SpineObjectModel.cs index 3f1bff6..a12b474 100644 --- a/SpineViewer/Models/SpineObjectModel.cs +++ b/SpineViewer/Models/SpineObjectModel.cs @@ -359,6 +359,8 @@ namespace SpineViewer.Models FlipY = _spineObject.Skeleton.ScaleY < 0, X = _spineObject.Skeleton.X, Y = _spineObject.Skeleton.Y, + + IsShown = _isShown, UsePma = _spineObject.UsePma, Physics = _spineObject.Physics.ToString(), @@ -399,6 +401,8 @@ namespace SpineViewer.Models SetProperty(_spineObject.Skeleton.ScaleY < 0, config.FlipY, v => _spineObject.Skeleton.ScaleY *= -1, nameof(FlipY)); SetProperty(_spineObject.Skeleton.X, config.X, v => _spineObject.Skeleton.X = v, nameof(X)); SetProperty(_spineObject.Skeleton.Y, config.Y, v => _spineObject.Skeleton.Y = v, nameof(Y)); + + IsShown = config.IsShown; SetProperty(_spineObject.UsePma, config.UsePma, v => _spineObject.UsePma = v, nameof(UsePma)); SetProperty(_spineObject.Physics, Enum.Parse(config.Physics ?? "Update", true), v => _spineObject.Physics = v, nameof(Physics)); diff --git a/SpineViewer/Services/DialogService.cs b/SpineViewer/Services/DialogService.cs index 02cb4c3..e818f5d 100644 --- a/SpineViewer/Services/DialogService.cs +++ b/SpineViewer/Services/DialogService.cs @@ -68,27 +68,47 @@ namespace SpineViewer.Services /// 是否确认了选择 public static bool ShowOpenFolderDialog(out string? folderName) { - // XXX: 此处使用了 System.Windows.Forms 的文件夹浏览对话框 - var folderDialog = new OpenFolderDialog() { Multiselect = false }; - if (folderDialog.ShowDialog() is true) + var dialog = new OpenFolderDialog() { Multiselect = false }; + if (dialog.ShowDialog() is true) { - folderName = folderDialog.FolderName; + folderName = dialog.FolderName; return true; } folderName = null; return false; } - /// - /// 获取用户选择的文件夹 - /// - /// - /// 是否确认了选择 - public static bool ShowSaveFileDialog(out string? selectedPath) + public static bool ShowOpenFileDialog(out string? fileName, string initialDirectory = "", string filter = "All|*.*") { - var dialog = new SaveFileDialog() { }; - selectedPath = null; - // TODO + var dialog = new OpenFileDialog() + { + InitialDirectory = initialDirectory, + Filter = filter + }; + if (dialog.ShowDialog() is true) + { + fileName = dialog.FileName; + return true; + } + fileName = null; + return false; + } + + public static bool ShowSaveFileDialog(ref string? fileName, string initialDirectory = "", string defaultExt = "", string filter = "All|*.*") + { + var dialog = new SaveFileDialog() + { + FileName = fileName, + InitialDirectory = initialDirectory, + DefaultExt = defaultExt, + Filter = filter, + }; + if (dialog.ShowDialog() is true) + { + fileName = dialog.FileName; + return true; + } + fileName = null; return false; } } diff --git a/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs b/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs index c87bf5a..135b850 100644 --- a/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs +++ b/SpineViewer/ViewModels/MainWindow/SpineObjectListViewModel.cs @@ -15,7 +15,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; -using System.Windows.Shapes; using System.Windows.Shell; namespace SpineViewer.ViewModels.MainWindow @@ -348,6 +347,74 @@ namespace SpineViewer.ViewModels.MainWindow return true; } + public RelayCommand Cmd_ApplySpineObjectConfigFromFile => _cmd_ApplySpineObjectConfigFromFile ??= new(ApplySpineObjectConfigFromFile_Execute, ApplySpineObjectConfigFromFile_CanExecute); + private RelayCommand? _cmd_ApplySpineObjectConfigFromFile; + + private void ApplySpineObjectConfigFromFile_Execute(IList? args) + { + if (!ApplySpineObjectConfigFromFile_CanExecute(args)) return; + if (!DialogService.ShowOpenFileDialog(out var fileName, filter: "Json Config|*.jcfg|All|*.*")) return; + try + { + var config = SpineObjectConfigModel.Deserialize(fileName); + foreach (SpineObjectModel sp in args) + { + sp.Load(config); + _logger.Info("Apply config to model: {0}", sp.Name); + } + } + catch (Exception ex) + { + _logger.Error("Failed to apply config file {0}, {1}", fileName, ex.Message); + _logger.Trace(ex.ToString()); + return; + } + } + + private bool ApplySpineObjectConfigFromFile_CanExecute(IList? args) + { + if (args is null) return false; + if (args.Count <= 0) return false; + return true; + } + + public RelayCommand Cmd_SaveSpineObjectConfigToFile => _cmd_SaveSpineObjectConfigToFile ??= new(SaveSpineObjectConfigToFile_Execute, SaveSpineObjectConfigToFile_CanExecute); + private RelayCommand? _cmd_SaveSpineObjectConfigToFile; + + private void SaveSpineObjectConfigToFile_Execute(IList? args) + { + if (!SaveSpineObjectConfigToFile_CanExecute(args)) return; + var sp = (SpineObjectModel)args[0]; + var config = sp.Dump(); + + string fileName = $"{Path.ChangeExtension(Path.GetFileName(sp.SkelPath), ".jcfg")}"; + if (!DialogService.ShowSaveFileDialog( + ref fileName, + initialDirectory: sp.AssetsDir, + defaultExt: ".jcfg", + filter:"Json Config|*.jcfg|All|*.*") + ) + return; + try + { + sp.Dump().Serialize(fileName); + _logger.Info("{0} config save to {1}", sp.Name, fileName); + } + catch (Exception ex) + { + _logger.Error("Failed to save config file {0}, {1}", fileName, ex.Message); + _logger.Trace(ex.ToString()); + return; + } + } + + private bool SaveSpineObjectConfigToFile_CanExecute(IList? args) + { + if (args is null) return false; + if (args.Count != 1) return false; + return true; + } + /// /// 从路径列表添加对象 /// diff --git a/SpineViewer/Views/MainWindow.xaml b/SpineViewer/Views/MainWindow.xaml index 5f996ee..3462723 100644 --- a/SpineViewer/Views/MainWindow.xaml +++ b/SpineViewer/Views/MainWindow.xaml @@ -288,9 +288,12 @@ InputGestureText="Ctrl+Shift+V" Command="{Binding Cmd_ApplySpineObjectConfig}" CommandParameter="{Binding PlacementTarget.SelectedItems, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/> - - - + +