From 0fe086bd8bc490bf6c0695cce829f096741bf667 Mon Sep 17 00:00:00 2001 From: Hakoyu Date: Fri, 29 Mar 2024 23:46:32 +0800 Subject: [PATCH] =?UTF-8?q?#=20=E6=9B=B4=E6=96=B0=20-=20=E5=AE=8C=E5=85=A8?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20-=20=E6=B7=BB=E5=8A=A0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E6=8F=90=E7=A4=BA(109->11000)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VPet.ModMaker/Converters.xaml | 5 +- VPet.ModMaker/Models/I18nData.cs | 2 +- VPet.ModMaker/Models/ModMakeHistory.cs | 24 +- VPet.ModMaker/Models/ModMaker.cs | 6 +- VPet.ModMaker/Models/ModModel/AnimeModel.cs | 54 +- .../Models/ModModel/AnimeTypeModel.cs | 150 ++--- .../Models/ModModel/FoodAnimeLocationModel.cs | 36 +- .../Models/ModModel/FoodAnimeModel.cs | 74 +-- .../Models/ModModel/FoodAnimeTypeModel.cs | 49 +- VPet.ModMaker/Models/ModModel/FoodModel.cs | 27 +- VPet.ModMaker/Models/ModModel/ImageModel.cs | 21 +- VPet.ModMaker/Models/ModModel/ModInfoModel.cs | 123 ++-- .../Models/ModModel/ModUpdataHelper.cs | 86 +++ VPet.ModMaker/Models/ModModel/MoveModel.cs | 110 ++-- VPet.ModMaker/Models/ModModel/PetModel.cs | 566 ++++++++++-------- .../Models/ModModel/SelectTextModel.cs | 1 - VPet.ModMaker/Models/ModModel/WorkModel.cs | 279 +++++---- VPet.ModMaker/Utils/NativeExtensions.cs | 18 + VPet.ModMaker/VPet.ModMaker.csproj | 2 +- .../ModEdit/AnimeEdit/AnimeEditWindowVM.cs | 133 ++-- .../ModEdit/AnimeEdit/AnimePageVM.cs | 179 +++--- .../AnimeEdit/FoodAnimeEditWindowVM.cs | 138 +++-- .../AnimeEdit/SelectGraphTypeWindowVM.cs | 107 ++++ .../ModEdit/I18nEdit/I18nEditWindowVM.cs | 10 +- .../ViewModels/ModEdit/ModEditWindowVM.cs | 15 +- .../ModEdit/MoveEdit/MoveEditWindowVM.cs | 50 +- .../ViewModels/ModEdit/MoveEdit/MovePageVM.cs | 101 ++-- .../ModEdit/PetEdit/PetEditWindowVM.cs | 60 +- .../ViewModels/ModEdit/PetEdit/PetPageVM.cs | 12 +- .../ModEdit/SaveTranslationModWindowVM.cs | 2 +- .../ModEdit/WorkEdit/WorkEditWindowVM.cs | 149 ++++- .../ViewModels/ModEdit/WorkEdit/WorkPageVM.cs | 88 ++- VPet.ModMaker/ViewModels/ModMakerWindowVM.cs | 148 +++-- .../Views/ModEdit/AddCultureWindow.xaml.cs | 6 +- .../ModEdit/AnimeEdit/AnimeEditWindow.xaml | 6 +- .../ModEdit/AnimeEdit/AnimeEditWindow.xaml.cs | 16 +- .../Views/ModEdit/AnimeEdit/AnimePage.xaml | 18 +- .../Views/ModEdit/AnimeEdit/AnimePage.xaml.cs | 4 +- .../AnimeEdit/FoodAnimeEditWindow.xaml.cs | 16 +- .../AnimeEdit/SelectGraphTypeWindow.xaml | 13 +- .../AnimeEdit/SelectGraphTypeWindow.xaml.cs | 53 +- .../ClickTextEdit/ClickTextEditWindow.xaml.cs | 4 +- .../ModEdit/ClickTextEdit/ClickTextPage.xaml | 8 +- .../ClickTextEdit/ClickTextPage.xaml.cs | 2 +- .../ModEdit/FoodEdit/FoodEditWindow.xaml.cs | 4 +- .../Views/ModEdit/FoodEdit/FoodPage.xaml.cs | 2 +- .../ModEdit/I18nEdit/I18nEditWindow.xaml.cs | 4 +- .../LowTextEdit/LowTextEditWindow.xaml.cs | 4 +- .../ModEdit/LowTextEdit/LowTextPage.xaml.cs | 2 +- .../Views/ModEdit/ModEditWindow.xaml | 5 +- .../Views/ModEdit/ModEditWindow.xaml.cs | 9 +- .../ModEdit/MoveEdit/MoveEditWindow.xaml.cs | 4 +- .../Views/ModEdit/MoveEdit/MovePage.xaml | 16 +- .../Views/ModEdit/MoveEdit/MovePage.xaml.cs | 4 +- .../Views/ModEdit/PetEdit/PetEditWindow.xaml | 150 ++--- .../ModEdit/PetEdit/PetEditWindow.xaml.cs | 4 +- .../Views/ModEdit/PetEdit/PetPage.xaml | 7 + .../Views/ModEdit/PetEdit/PetPage.xaml.cs | 4 +- .../SelectTextEditWindow.xaml.cs | 4 +- .../SelectTextEdit/SelectTextPage.xaml | 4 +- .../SelectTextEdit/SelectTextPage.xaml.cs | 2 +- .../ModEdit/WorkEdit/WorkEditWindow.xaml | 11 +- .../ModEdit/WorkEdit/WorkEditWindow.xaml.cs | 21 +- .../Views/ModEdit/WorkEdit/WorkPage.xaml | 12 +- .../Views/ModEdit/WorkEdit/WorkPage.xaml.cs | 4 +- VPet.ModMaker/Views/ModMakerWindow.xaml | 6 +- VPet.ModMaker/Views/ModMakerWindow.xaml.cs | 7 +- 67 files changed, 1808 insertions(+), 1453 deletions(-) create mode 100644 VPet.ModMaker/Models/ModModel/ModUpdataHelper.cs create mode 100644 VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/SelectGraphTypeWindowVM.cs diff --git a/VPet.ModMaker/Converters.xaml b/VPet.ModMaker/Converters.xaml index 1569752..edc69e2 100644 --- a/VPet.ModMaker/Converters.xaml +++ b/VPet.ModMaker/Converters.xaml @@ -12,6 +12,9 @@ - + \ No newline at end of file diff --git a/VPet.ModMaker/Models/I18nData.cs b/VPet.ModMaker/Models/I18nData.cs index 27008af..d2cd1a7 100644 --- a/VPet.ModMaker/Models/I18nData.cs +++ b/VPet.ModMaker/Models/I18nData.cs @@ -32,5 +32,5 @@ public class I18nData : ObservableObjectX /// /// 基于 的索引的数据列表 /// - public ObservableCollection> Datas { get; } = new(); + public ObservableList> Datas { get; } = new(); } diff --git a/VPet.ModMaker/Models/ModMakeHistory.cs b/VPet.ModMaker/Models/ModMakeHistory.cs index 583a219..b84180e 100644 --- a/VPet.ModMaker/Models/ModMakeHistory.cs +++ b/VPet.ModMaker/Models/ModMakeHistory.cs @@ -12,23 +12,23 @@ namespace VPet.ModMaker.Models; /// /// 模组制作历史 /// -public class ModMakeHistory +public class ModMakeHistory : IEquatable { /// /// 图片 /// - public BitmapImage Image { get; set; } + public BitmapImage? Image { get; set; } /// /// Id /// [Line(ignoreCase: true)] - public string Id { get; set; } + public string ID { get; set; } = string.Empty; /// /// 路径 /// - private string _path; + private string _path = string.Empty; /// /// 资源路径 @@ -56,4 +56,20 @@ public class ModMakeHistory /// [Line(ignoreCase: true)] public DateTime LastTime { get; set; } = DateTime.Now; + + public bool Equals(ModMakeHistory? other) + { + return SourcePath.Equals(other?.SourcePath); + } + + /// + public override bool Equals(object? obj) + { + return Equals(obj as ModMakeHistory); + } + + public override int GetHashCode() + { + return SourcePath.GetHashCode(); + } } diff --git a/VPet.ModMaker/Models/ModMaker.cs b/VPet.ModMaker/Models/ModMaker.cs index 14f14ea..f1ddf35 100644 --- a/VPet.ModMaker/Models/ModMaker.cs +++ b/VPet.ModMaker/Models/ModMaker.cs @@ -17,7 +17,7 @@ public class ModMaker : MainPlugin //public ILine Set; public override string PluginName => "ModMaker"; - public ModMakerWindow Maker; + public ModMakerWindow Maker = null!; public ModMaker(IMainWindow mainwin) : base(mainwin) { } @@ -61,8 +61,8 @@ public class ModMaker : MainPlugin } } - private void Maker_Closed(object sender, EventArgs e) + private void Maker_Closed(object? sender, EventArgs e) { - Maker = null; + Maker = null!; } } diff --git a/VPet.ModMaker/Models/ModModel/AnimeModel.cs b/VPet.ModMaker/Models/ModModel/AnimeModel.cs index 5b36ad6..bfbf41a 100644 --- a/VPet.ModMaker/Models/ModModel/AnimeModel.cs +++ b/VPet.ModMaker/Models/ModModel/AnimeModel.cs @@ -10,16 +10,34 @@ namespace VPet.ModMaker.Models.ModModel; /// /// 动画模型 /// -public class AnimeModel : ObservableObjectX +public class AnimeModel : ObservableObjectX, ICloneable { - #region Id + public AnimeModel() { } + + public AnimeModel(string imagesPath) + : this() + { + foreach (var file in Directory.EnumerateFiles(imagesPath)) + { + var info = Path.GetFileNameWithoutExtension(file).Split(NativeUtils.Separator); + ID = info[0]; + var duration = info.Last(); + var imageModel = new ImageModel( + NativeUtils.LoadImageToMemoryStream(file), + int.Parse(duration) + ); + Images.Add(imageModel); + } + } + + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _id; + private string _id = string.Empty; /// /// Id /// - public string Id + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -43,40 +61,24 @@ public class AnimeModel : ObservableObjectX /// /// 图像列表 /// - public ObservableCollection Images { get; } = new(); - - public AnimeModel() { } - - public AnimeModel(string imagesPath) - : this() - { - foreach (var file in Directory.EnumerateFiles(imagesPath)) - { - var info = Path.GetFileNameWithoutExtension(file).Split(NativeUtils.Separator); - Id = info[0]; - var duration = info.Last(); - var imageModel = new ImageModel( - NativeUtils.LoadImageToMemoryStream(file), - int.Parse(duration) - ); - Images.Add(imageModel); - } - } + public ObservableList Images { get; } = new(); /// /// 复制 /// /// - public AnimeModel Copy() + public AnimeModel Clone() { var model = new AnimeModel(); - model.Id = Id; + model.ID = ID; model.AnimeType = AnimeType; foreach (var image in Images) - model.Images.Add(image.Copy()); + model.Images.Add(image.Clone()); return model; } + object ICloneable.Clone() => Clone(); + /// /// 关闭所有图像流 /// diff --git a/VPet.ModMaker/Models/ModModel/AnimeTypeModel.cs b/VPet.ModMaker/Models/ModModel/AnimeTypeModel.cs index 6c74210..ab6f1f7 100644 --- a/VPet.ModMaker/Models/ModModel/AnimeTypeModel.cs +++ b/VPet.ModMaker/Models/ModModel/AnimeTypeModel.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -16,64 +18,94 @@ namespace VPet.ModMaker.Models.ModModel; public class AnimeTypeModel : ObservableObjectX { + public AnimeTypeModel() + { + PropertyChanged += AnimeTypeModel_PropertyChanged; + } + + private void AnimeTypeModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Name)) + { + ID = $"{GraphType}_{Name}"; + } + } + + public AnimeTypeModel(AnimeTypeModel model) + : this() + { + ID = model.ID; + Name = model.Name; + GraphType = model.GraphType; + foreach (var anime in model.HappyAnimes) + HappyAnimes.Add(anime.Clone()); + foreach (var anime in model.NomalAnimes) + NomalAnimes.Add(anime.Clone()); + foreach (var anime in model.PoorConditionAnimes) + PoorConditionAnimes.Add(anime.Clone()); + foreach (var anime in model.IllAnimes) + IllAnimes.Add(anime.Clone()); + } + /// /// 动作类型 /// - public static ObservableCollection GraphTypes { get; } = - new(Enum.GetValues()); + public static FrozenSet GraphTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 动画类型 /// - public static ObservableCollection AnimatTypes { get; } = - new(Enum.GetValues(typeof(GraphInfo.AnimatType)).Cast()); + public static FrozenSet AnimatTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 模式类型 /// - public static ObservableCollection ModeTypes { get; } = - new(Enum.GetValues(typeof(ModeType)).Cast()); + public static FrozenSet ModeTypes { get; } = Enum.GetValues().ToFrozenSet(); /// /// 含有名称的动作列表 /// - public static HashSet HasNameAnimes { get; } = - new() - { - GraphInfo.GraphType.Common, - GraphInfo.GraphType.Work, - GraphInfo.GraphType.Idel, - GraphInfo.GraphType.Move, - GraphInfo.GraphType.Say - }; + public static FrozenSet HasNameAnimes { get; } = + FrozenSet.ToFrozenSet( + [ + GraphInfo.GraphType.Common, + GraphInfo.GraphType.Work, + GraphInfo.GraphType.Idel, + GraphInfo.GraphType.Move, + GraphInfo.GraphType.Say + ] + ); /// /// 含有不同动画类型的动作列表 /// - public static HashSet HasMultiTypeAnimes { get; } = - new() - { - GraphInfo.GraphType.Touch_Head, - GraphInfo.GraphType.Touch_Body, - GraphInfo.GraphType.Sleep, - GraphInfo.GraphType.Raised_Static, - GraphInfo.GraphType.StateONE, - GraphInfo.GraphType.StateTWO, - GraphInfo.GraphType.Common, - GraphInfo.GraphType.Work, - GraphInfo.GraphType.Idel, - GraphInfo.GraphType.Move, - GraphInfo.GraphType.Say - }; + public static FrozenSet HasMultiTypeAnimes { get; } = + FrozenSet.ToFrozenSet( + [ + GraphInfo.GraphType.Touch_Head, + GraphInfo.GraphType.Touch_Body, + GraphInfo.GraphType.Sleep, + GraphInfo.GraphType.Raised_Static, + GraphInfo.GraphType.StateONE, + GraphInfo.GraphType.StateTWO, + GraphInfo.GraphType.Common, + GraphInfo.GraphType.Work, + GraphInfo.GraphType.Idel, + GraphInfo.GraphType.Move, + GraphInfo.GraphType.Say + ] + ); - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _id; + private string _id = string.Empty; /// /// Id /// - public string Id + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -82,7 +114,7 @@ public class AnimeTypeModel : ObservableObjectX #region Name [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _name; + private string _name = string.Empty; /// /// 名称 @@ -96,61 +128,37 @@ public class AnimeTypeModel : ObservableObjectX #region GraphType [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private GraphInfo.GraphType _GraphType; + private GraphInfo.GraphType _graphType; /// /// 动作类型 /// public GraphInfo.GraphType GraphType { - get => _GraphType; - set => SetProperty(ref _GraphType, value); + get => _graphType; + set => SetProperty(ref _graphType, value); } #endregion /// /// 开心动画 /// - public ObservableCollection HappyAnimes { get; } = new(); + public ObservableList HappyAnimes { get; } = new(); /// /// 普通动画 (默认) /// - public ObservableCollection NomalAnimes { get; } = new(); + public ObservableList NomalAnimes { get; } = new(); /// /// 低状态动画 /// - public ObservableCollection PoorConditionAnimes { get; } = new(); + public ObservableList PoorConditionAnimes { get; } = new(); /// /// 生病动画 /// - public ObservableCollection IllAnimes { get; } = new(); - - public AnimeTypeModel() - { //TODO - //Name.ValueChanged += (_, _) => - //{ - // Id.Value = $"{GraphType.Value}_{Name.Value}"; - //}; - } - - public AnimeTypeModel(AnimeTypeModel model) - : this() - { - Id = model.Id; - Name = model.Name; - GraphType = model.GraphType; - foreach (var anime in model.HappyAnimes) - HappyAnimes.Add(anime.Copy()); - foreach (var anime in model.NomalAnimes) - NomalAnimes.Add(anime.Copy()); - foreach (var anime in model.PoorConditionAnimes) - PoorConditionAnimes.Add(anime.Copy()); - foreach (var anime in model.IllAnimes) - IllAnimes.Add(anime.Copy()); - } + public ObservableList IllAnimes { get; } = new(); /// /// 创建动画类型模型 @@ -196,9 +204,9 @@ public class AnimeTypeModel : ObservableObjectX Name = Path.GetFileName(path); // 为带有名字的类型设置Id if (graphType.IsHasNameAnime()) - Id = $"{graphType}_{Name}"; + ID = $"{graphType}_{Name}"; else - Id = graphType.ToString(); + ID = graphType.ToString(); GraphType = graphType; if ( graphType @@ -389,7 +397,7 @@ public class AnimeTypeModel : ObservableObjectX /// 路径 /// 动画类型 private static void AddAnime( - ObservableCollection collection, + ObservableList collection, string path, GraphInfo.AnimatType animatType = AnimatType.Single ) @@ -572,7 +580,7 @@ public class AnimeTypeModel : ObservableObjectX SaveAnimes(modePath, animeTypeModel.IllAnimes); } - static void SaveAnimes(string animePath, ObservableCollection animes) + static void SaveAnimes(string animePath, ObservableList animes) { Directory.CreateDirectory(animePath); var countA = 0; @@ -632,7 +640,7 @@ public class AnimeTypeModel : ObservableObjectX var modePath = Path.Combine(animePath, nameof(ModeType.Ill)); SaveAnimes(modePath, animeType.IllAnimes); } - static void SaveAnimes(string animePath, ObservableCollection animes) + static void SaveAnimes(string animePath, ObservableList animes) { Directory.CreateDirectory(animePath); foreach (var anime in animes.EnumerateIndex()) @@ -651,7 +659,7 @@ public class AnimeTypeModel : ObservableObjectX foreach (var image in model.Images.EnumerateIndex()) { image.Value.Image.SaveToPng( - Path.Combine(imagesPath, $"{model.Id}_{image.Index:000}_{image.Value.Duration}.png") + Path.Combine(imagesPath, $"{model.ID}_{image.Index:000}_{image.Value.Duration}.png") ); } } diff --git a/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs b/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs index 8a92e9e..c2f7d8a 100644 --- a/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodAnimeLocationModel.cs @@ -11,8 +11,12 @@ namespace VPet.ModMaker.Models.ModModel; /// /// 食物图像位置模型 /// -public class FoodAnimeLocationModel : ObservableObjectX +public class FoodAnimeLocationModel + : ObservableObjectX, + ICloneable { + public FoodAnimeLocationModel() { } + #region Duration [DebuggerBrowsable(DebuggerBrowsableState.Never)] private int _duration; @@ -30,7 +34,7 @@ public class FoodAnimeLocationModel : ObservableObjectX /// /// 范围 /// - public ObservableRectangleLocation Rect { get; set; } = new(); + public ObservableRectangleLocation RectangleLocation { get; set; } = new(); /// /// 旋转角度 @@ -59,27 +63,27 @@ public class FoodAnimeLocationModel : ObservableObjectX set => SetProperty(ref _opacity, value); } #endregion - - public FoodAnimeLocationModel() + public FoodAnimeLocationModel Clone() { - Rect.PropertyChangedX += (s, e) => + var model = new FoodAnimeLocationModel { - Rect.Height = (int)e.NewValue; + Duration = Duration, + RectangleLocation = new( + RectangleLocation.X, + RectangleLocation.Y, + RectangleLocation.Width, + RectangleLocation.Width + ), + Rotate = Rotate, + Opacity = Opacity }; - } - - public FoodAnimeLocationModel Copy() - { - var model = new FoodAnimeLocationModel(); - model.Duration = Duration; - model.Rect = new(Rect.X, Rect.Y, Rect.Width, Rect.Height); - model.Rotate = Rotate; - model.Opacity = Opacity; return model; } + object ICloneable.Clone() => Clone(); + public override string ToString() { - return $"{Duration}, {Rect.X}, {Rect.Y}, {Rect.Width}, {Rotate}, {Opacity}"; + return $"{Duration}, {RectangleLocation.X}, {RectangleLocation.Y}, {RectangleLocation.Width}, {Rotate}, {Opacity}"; } } diff --git a/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs b/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs index 15ab9e7..cb58c74 100644 --- a/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodAnimeModel.cs @@ -13,42 +13,14 @@ using static VPet_Simulator.Core.IGameSave; namespace VPet.ModMaker.Models.ModModel; -public class FoodAnimeModel : ObservableObjectX +public class FoodAnimeModel : ObservableObjectX, ICloneable { - #region Id - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _Id; - - public string Id - { - get => _Id; - set => SetProperty(ref _Id, value); - } - #endregion - - public ObservableValue Mode { get; } - - /// - /// 后图像列表 - /// - public ObservableCollection BackImages { get; set; } = new(); - - /// - /// 前图像列表 - /// - public ObservableCollection FrontImages { get; set; } = new(); - - /// - /// 食物定位列表 - /// - public ObservableCollection FoodLocations { get; } = new(); - public FoodAnimeModel() { } public FoodAnimeModel(ILine line) : this() { - foreach (var item in line.Where(i => i.Name.StartsWith("a"))) + foreach (var item in line.Where(i => i.Name.StartsWith('a'))) { //var index = int.Parse(item.Name.Substring(1)); var infos = item.Info.Split(','); @@ -56,7 +28,7 @@ public class FoodAnimeModel : ObservableObjectX foodLocationInfo.Duration = int.Parse(infos[0]); if (infos.Length > 1) { - foodLocationInfo.Rect = new( + foodLocationInfo.RectangleLocation = new( double.Parse(infos[1]), double.Parse(infos[2]), double.Parse(infos[3]), @@ -71,23 +43,53 @@ public class FoodAnimeModel : ObservableObjectX } } + #region ID + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _id; + + public string ID + { + get => _id; + set => SetProperty(ref _id, value); + } + #endregion + + public ObservableValue Mode { get; } + + /// + /// 后图像列表 + /// + public ObservableList BackImages { get; set; } = new(); + + /// + /// 前图像列表 + /// + public ObservableList FrontImages { get; set; } = new(); + + /// + /// 食物定位列表 + /// + public ObservableList FoodLocations { get; } = new(); + /// /// 复制 /// /// - public FoodAnimeModel Copy() + public FoodAnimeModel Clone() { var model = new FoodAnimeModel(); - model.Id = Id; + model.ID = ID; foreach (var image in FrontImages) - model.FrontImages.Add(image.Copy()); + model.FrontImages.Add(image.Clone()); foreach (var image in BackImages) - model.BackImages.Add(image.Copy()); + model.BackImages.Add(image.Clone()); foreach (var foodLocation in FoodLocations) - model.FoodLocations.Add(foodLocation.Copy()); + model.FoodLocations.Add(foodLocation.Clone()); return model; } + object ICloneable.Clone() => Clone(); + /// /// 关闭所有图像流 /// diff --git a/VPet.ModMaker/Models/ModModel/FoodAnimeTypeModel.cs b/VPet.ModMaker/Models/ModModel/FoodAnimeTypeModel.cs index 9a9d820..efb740d 100644 --- a/VPet.ModMaker/Models/ModModel/FoodAnimeTypeModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodAnimeTypeModel.cs @@ -17,6 +17,8 @@ namespace VPet.ModMaker.Models.ModModel; public class FoodAnimeTypeModel : ObservableObjectX { + public FoodAnimeTypeModel() { } + /// /// 动作类型 /// @@ -38,11 +40,11 @@ public class FoodAnimeTypeModel : ObservableObjectX /// public const string BackLayName = "back_lay"; - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _id; - public string Id + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -59,37 +61,34 @@ public class FoodAnimeTypeModel : ObservableObjectX public string Name { get => _name; - set => SetProperty(ref _name, value); + set + { + if (SetProperty(ref _name, value) is false) + return; + ID = $"{GraphType}_{Name}"; + } } #endregion /// /// 开心动画 /// - public ObservableCollection HappyAnimes { get; } = new(); + public ObservableList HappyAnimes { get; } = new(); /// /// 普通动画 (默认) /// - public ObservableCollection NomalAnimes { get; } = new(); + public ObservableList NomalAnimes { get; } = new(); /// /// 低状态动画 /// - public ObservableCollection PoorConditionAnimes { get; } = new(); + public ObservableList PoorConditionAnimes { get; } = new(); /// /// 生病动画 /// - public ObservableCollection IllAnimes { get; } = new(); - - public FoodAnimeTypeModel() - { //TODO - //Name.ValueChanged += (_, _) => - //{ - // Id.Value = $"{GraphType}_{Name.Value}"; - //}; - } + public ObservableList IllAnimes { get; } = new(); public void Close() { @@ -131,16 +130,16 @@ public class FoodAnimeTypeModel : ObservableObjectX public FoodAnimeTypeModel(FoodAnimeTypeModel model) : this() { - Id = model.Id; + ID = model.ID; Name = model.Name; foreach (var anime in model.HappyAnimes) - HappyAnimes.Add(anime.Copy()); + HappyAnimes.Add(anime.Clone()); foreach (var anime in model.NomalAnimes) - NomalAnimes.Add(anime.Copy()); + NomalAnimes.Add(anime.Clone()); foreach (var anime in model.PoorConditionAnimes) - PoorConditionAnimes.Add(anime.Copy()); + PoorConditionAnimes.Add(anime.Clone()); foreach (var anime in model.IllAnimes) - IllAnimes.Add(anime.Copy()); + IllAnimes.Add(anime.Clone()); } /// @@ -217,7 +216,7 @@ public class FoodAnimeTypeModel : ObservableObjectX public void AddModeAnime( string path, ModeType mode, - ObservableCollection foodAnimes, + ObservableList foodAnimes, ILine line, List pngAnimeInfos ) @@ -250,7 +249,7 @@ public class FoodAnimeTypeModel : ObservableObjectX } foodAnimes.Add(anime); - static ObservableCollection GetImages(string path, PNGAnimeInfo pngAnimeInfo) + static ObservableList GetImages(string path, PNGAnimeInfo pngAnimeInfo) { return new( Directory @@ -299,7 +298,7 @@ public class FoodAnimeTypeModel : ObservableObjectX /// 模式 private void SaveAnimeInfo( string animePath, - ObservableCollection animes, + ObservableList animes, ModeType mode ) { @@ -334,7 +333,7 @@ public class FoodAnimeTypeModel : ObservableObjectX frontImage.Value.Image.SaveToPng( Path.Combine( frontLayPath, - $"{anime.Id}_{frontImage.Index:000}_{frontImage.Value.Duration}.png" + $"{anime.ID}_{frontImage.Index:000}_{frontImage.Value.Duration}.png" ) ); } @@ -343,7 +342,7 @@ public class FoodAnimeTypeModel : ObservableObjectX backImage.Value.Image.SaveToPng( Path.Combine( backLayPath, - $"{anime.Id}_{backImage.Index:000}_{backImage.Value.Duration}.png" + $"{anime.ID}_{backImage.Index:000}_{backImage.Value.Duration}.png" ) ); } diff --git a/VPet.ModMaker/Models/ModModel/FoodModel.cs b/VPet.ModMaker/Models/ModModel/FoodModel.cs index 5bf55bb..77497f0 100644 --- a/VPet.ModMaker/Models/ModModel/FoodModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodModel.cs @@ -25,25 +25,6 @@ public class FoodModel : I18nModel { public FoodModel() { - //DescriptionId = $"{Id}_{nameof(DescriptionId)}"; - //TODO - //Id.ValueChanged += (s, e) => - //{ - // DescriptionId.Value = $"{e.NewValue}_{nameof(DescriptionId)}"; - //}; - //ReferencePrice.AddNotifySender( - // Strength, - // StrengthFood, - // StrengthDrink, - // Feeling, - // Health, - // Likability, - // Exp - //); - //ReferencePrice.SenderPropertyChanged += (s, _) => - //{ - // s.Value = Math.Floor(SetValueToFood(_food).RealPrice); - //}; PropertyChangedX += FoodModel_PropertyChangedX; } @@ -64,11 +45,7 @@ public class FoodModel : I18nModel PropertyChangedXEventArgs e ) { - if (e.PropertyName == nameof(ID)) - { - DescriptionID = $"{e.NewValue}_{nameof(DescriptionID)}"; - } - else if (_notifyReferencePrice.Contains(e.PropertyName)) + if (e.PropertyName is not null && _notifyReferencePrice.Contains(e.PropertyName)) { this.Adapt(_food); ReferencePrice = Math.Floor(_food.RealPrice); @@ -96,7 +73,7 @@ public class FoodModel : I18nModel /// /// 食物类型 /// - public static ObservableCollection FoodTypes { get; } = + public static ObservableList FoodTypes { get; } = new(Enum.GetValues(typeof(Food.FoodType)).Cast()); #region ID diff --git a/VPet.ModMaker/Models/ModModel/ImageModel.cs b/VPet.ModMaker/Models/ModModel/ImageModel.cs index 87c74ae..b5fcb9a 100644 --- a/VPet.ModMaker/Models/ModModel/ImageModel.cs +++ b/VPet.ModMaker/Models/ModModel/ImageModel.cs @@ -13,11 +13,17 @@ namespace VPet.ModMaker.Models.ModModel; /// /// 图像模型 /// -public class ImageModel : ObservableObjectX +public class ImageModel : ObservableObjectX, ICloneable { + public ImageModel(BitmapImage image, int duration = 100) + { + Image = image; + Duration = duration; + } + #region Image [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _image; + private BitmapImage _image = null!; /// /// 图像 @@ -42,19 +48,14 @@ public class ImageModel : ObservableObjectX set => SetProperty(ref _duration, value); } #endregion - - public ImageModel(BitmapImage image, int duration = 100) - { - Image = image; - Duration = duration; - } - - public ImageModel Copy() + public ImageModel Clone() { var model = new ImageModel(Image.CloneStream(), Duration); return model; } + object ICloneable.Clone() => Clone(); + public void Close() { Image?.CloseStream(); diff --git a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs index cd7fe6c..d5d794a 100644 --- a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs +++ b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -26,6 +27,29 @@ namespace VPet.ModMaker.Models; /// public class ModInfoModel : I18nModel { + public ModInfoModel() + { + PropertyChanged += ModInfoModel_PropertyChanged; + Pets.CollectionChanged += Pets_CollectionChanged; + } + + private void ModInfoModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ID)) + { + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; + } + else if (e.PropertyName == nameof(ShowMainPet)) + { + Pets_CollectionChanged(null, null!); + } + } + + /// + /// 当前 + /// + public static ModInfoModel Current { get; set; } = new(); + #region AutoSetFoodPrice [DebuggerBrowsable(DebuggerBrowsableState.Never)] private bool _autoSetFoodPrice; @@ -65,33 +89,28 @@ public class ModInfoModel : I18nModel /// public ulong ItemID { get; } - /// - /// 当前 - /// - public static ModInfoModel Current { get; set; } = new(); - - #region Id + #region ID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _id = string.Empty; /// /// Id /// - public string Id + public string ID { get => _id; set => SetProperty(ref _id, value); } #endregion - #region DescriptionId + #region DescriptionID [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string _descriptionId = string.Empty; /// /// 描述Id /// - public string DescriptionId + public string DescriptionID { get => _descriptionId; set => SetProperty(ref _descriptionId, value); @@ -145,9 +164,9 @@ public class ModInfoModel : I18nModel /// #region Image [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _image; + private BitmapImage? _image; - public BitmapImage Image + public BitmapImage? Image { get => _image; set => SetProperty(ref _image, value); @@ -174,27 +193,27 @@ public class ModInfoModel : I18nModel /// /// 食物 /// - public ObservableCollection Foods { get; } = new(); + public ObservableList Foods { get; } = new(); /// /// 点击文本 /// - public ObservableCollection ClickTexts { get; } = new(); + public ObservableList ClickTexts { get; } = new(); /// /// 低状态文本 /// - public ObservableCollection LowTexts { get; } = new(); + public ObservableList LowTexts { get; } = new(); /// /// 选择文本 /// - public ObservableCollection SelectTexts { get; } = new(); + public ObservableList SelectTexts { get; } = new(); /// /// 宠物 /// - public ObservableCollection Pets { get; } = new(); + public ObservableList Pets { get; } = new(); /// /// 宠物实际数量 @@ -220,27 +239,8 @@ public class ModInfoModel : I18nModel /// public static Dictionary> SaveI18nDatas { get; } = new(); #endregion - public ModInfoModel() - { - DescriptionId = $"{Id}_{nameof(DescriptionId)}"; - //TODO - //Id.ValueChanged += (o, n) => - //{ - // DescriptionId.Value = $"{n}_{nameof(DescriptionId)}"; - //}; - //Pets.CollectionChanged += Pets_CollectionChanged; - //ShowMainPet.ValueChanged += ShowMainPet_ValueChanged; - } - private void ShowMainPet_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - Pets_CollectionChanged(null, null); - } - - private void Pets_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + private void Pets_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (ShowMainPet) PetDisplayedCount = Pets.Count; @@ -252,8 +252,8 @@ public class ModInfoModel : I18nModel : this() { SourcePath = loader.ModPath.FullName; - Id = loader.Name; - DescriptionId = loader.Intro; + ID = loader.Name; + DescriptionID = loader.Intro; Author = loader.Author; GameVersion = loader.GameVer; ModVersion = loader.Ver; @@ -280,22 +280,25 @@ public class ModInfoModel : I18nModel { // 若宠物的值为默认值并且本体同名宠物不为默认值, 则把本体宠物的值作为模组宠物的默认值 if ( - petModel.TouchHeadRect == PetModel.Default.TouchHeadRect - && petModel.TouchHeadRect != mainPet.TouchHeadRect + petModel.TouchHeadRectangleLocation + == PetModel.Current.TouchHeadRectangleLocation + && petModel.TouchHeadRectangleLocation != mainPet.TouchHeadRectangleLocation ) - petModel.TouchHeadRect = mainPet.TouchHeadRect; + petModel.TouchHeadRectangleLocation = mainPet.TouchHeadRectangleLocation; if ( - petModel.TouchBodyRect == PetModel.Default.TouchBodyRect - && petModel.TouchBodyRect != mainPet.TouchBodyRect + petModel.TouchBodyRectangleLocation + == PetModel.Current.TouchBodyRectangleLocation + && petModel.TouchBodyRectangleLocation != mainPet.TouchBodyRectangleLocation ) - petModel.TouchBodyRect = mainPet.TouchBodyRect; + petModel.TouchBodyRectangleLocation = mainPet.TouchBodyRectangleLocation; if ( - petModel.TouchRaisedRect == PetModel.Default.TouchRaisedRect - && petModel.TouchRaisedRect != mainPet.TouchRaisedRect + petModel.TouchRaisedRectangleLocation + == PetModel.Current.TouchRaisedRectangleLocation + && petModel.TouchRaisedRectangleLocation != mainPet.TouchRaisedRectangleLocation ) - petModel.TouchRaisedRect = mainPet.TouchRaisedRect; + petModel.TouchRaisedRectangleLocation = mainPet.TouchRaisedRectangleLocation; if ( - petModel.RaisePoint == PetModel.Default.RaisePoint + petModel.RaisePoint == PetModel.Current.RaisePoint && petModel.RaisePoint != mainPet.RaisePoint ) petModel.RaisePoint = mainPet.RaisePoint; @@ -328,7 +331,7 @@ public class ModInfoModel : I18nModel public void RefreshId() { - DescriptionId = $"{Id}_{nameof(DescriptionId)}"; + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; } #region Load @@ -500,15 +503,15 @@ public class ModInfoModel : I18nModel continue; if (i18nData.TryGetValue(pet.ID, out var name)) data.Name = name; - if (i18nData.TryGetValue(pet.PetNameId, out var petName)) + if (i18nData.TryGetValue(pet.PetNameID, out var petName)) data.PetName = petName; - if (i18nData.TryGetValue(pet.DescriptionId, out var description)) + if (i18nData.TryGetValue(pet.DescriptionID, out var description)) data.Description = description; foreach (var work in pet.Works) { if (work.I18nDatas.TryGetValue(key, out var workData) is false) continue; - if (i18nData.TryGetValue(work.Id, out var workName)) + if (i18nData.TryGetValue(work.ID, out var workName)) workData.Name = workName; } } @@ -521,7 +524,7 @@ public class ModInfoModel : I18nModel foreach (var selectText in SelectTexts) selectText.RefreshID(); foreach (var pet in Pets) - pet.RefreshId(); + pet.RefreshID(); } #endregion #region Save @@ -567,13 +570,13 @@ public class ModInfoModel : I18nModel var lps = new LPS() { - new Line("vupmod", Id) + new Line("vupmod", ID) { new Sub("author", Author), new Sub("gamever", GameVersion), new Sub("ver", ModVersion) }, - new Line("intro", DescriptionId), + new Line("intro", DescriptionID), new Line("authorid", AuthorID.ToString()), new Line("itemid", ItemID.ToString()), new Line("cachedate", DateTime.Now.Date.ToString("s")) @@ -583,8 +586,8 @@ public class ModInfoModel : I18nModel lps.Add( new Line("lang", cultureName) { - new Sub(Id, I18nDatas[cultureName].Name), - new Sub(DescriptionId, I18nDatas[cultureName].Description), + new Sub(ID, I18nDatas[cultureName].Name), + new Sub(DescriptionID, I18nDatas[cultureName].Description), } ); } @@ -768,7 +771,7 @@ public class ModInfoModel : I18nModel Directory.CreateDirectory(foodPath); foreach (var food in Foods) { - food.Image.SaveToPng(Path.Combine(foodPath, food.ID)); + food.Image?.SaveToPng(Path.Combine(foodPath, food.ID)); } } } @@ -778,12 +781,12 @@ public class ModInfoModel : I18nModel /// public void Close() { - Image.CloseStream(); + Image?.CloseStream(); foreach (var food in Foods) food.Close(); foreach (var pet in Pets) pet.Close(); - Current = null; + Current = null!; } public void SaveTranslationMod(string path, IEnumerable cultures) diff --git a/VPet.ModMaker/Models/ModModel/ModUpdataHelper.cs b/VPet.ModMaker/Models/ModModel/ModUpdataHelper.cs new file mode 100644 index 0000000..d54871c --- /dev/null +++ b/VPet.ModMaker/Models/ModModel/ModUpdataHelper.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using HKW.HKWUtils.Extensions; +using LinePutScript.Localization.WPF; +using VPet.ModMaker.ViewModels.ModEdit; +using VPet.ModMaker.Views; +using VPet.ModMaker.Views.ModEdit; + +namespace VPet.ModMaker.Models; + +/// +/// 模组升级助手 +/// +public static class ModUpdataHelper +{ + public static int LastVersion => UpdataAction.Last().Key; + + /// + /// 能否升级模组 + /// + /// 模组 + /// 版本 + /// 可以升级为 不可以为 + public static bool CanUpdata(ModInfoModel mod) + { + if (mod.ModVersion >= LastVersion) + return false; + return true; + } + + /// + /// 升级模组 + /// + /// 模组 + /// 版本 + /// 可以升级为 不可以为 + public static bool Updata(ModInfoModel mod) + { + if (CanUpdata(mod) is false) + return false; + foreach (var action in UpdataAction) + { + if (mod.ModVersion >= action.Key) + continue; + try + { + // 更新模组 + action.Value(mod); + // 更新支持的游戏版本 + mod.GameVersion = action.Key; + } + catch (Exception ex) + { + MessageBox.Show( + ModEditWindow.Current, + "模组更新失败\n当前版本: {0}\n目标版本: {1}\n{2}".Translate(mod.ModVersion, action.Key, ex) + ); + return false; + } + } + return true; + } + + public static SortedDictionary> UpdataAction { get; } = + new() + { + [11000] = (ModInfoModel m) => + { + // 修改宠物默认ID + foreach (var pet in m.Pets) + { + if (pet.ID == "默认虚拟桌宠") + pet.ID = "vup"; + foreach (var work in pet.Works) + { + // 修复工作溢出 + work.FixOverLoad(); + } + } + }, + }; +} diff --git a/VPet.ModMaker/Models/ModModel/MoveModel.cs b/VPet.ModMaker/Models/ModModel/MoveModel.cs index 8bb4d49..6145878 100644 --- a/VPet.ModMaker/Models/ModModel/MoveModel.cs +++ b/VPet.ModMaker/Models/ModModel/MoveModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -15,20 +16,65 @@ namespace VPet.ModMaker.Models; /// public class MoveModel : ObservableObjectX { + public MoveModel() { } + + public MoveModel(MoveModel model) + : this() + { + //Id.EnumValue = model.Id.EnumValue; + Graph = model.Graph; + Distance = model.Distance; + Interval = model.Interval; + CheckLeft = model.CheckLeft; + CheckRight = model.CheckRight; + CheckTop = model.CheckTop; + CheckBottom = model.CheckBottom; + SpeedX = model.SpeedX; + SpeedY = model.SpeedY; + LocateLength = model.LocateLength; + TriggerLeft = model.TriggerLeft; + TriggerRight = model.TriggerRight; + TriggerTop = model.TriggerTop; + TriggerBottom = model.TriggerBottom; + LocateType.Value = model.LocateType.Value; + TriggerType.Value = model.TriggerType.Value; + ModeType.Value = model.ModeType.Value; + } + + public MoveModel(GraphHelper.Move move) + : this() + { + //Id.EnumValue = move.Id.EnumValue; + Graph = move.Graph; + Distance = move.Distance; + Interval = move.Interval; + CheckLeft = move.CheckLeft; + CheckRight = move.CheckRight; + CheckTop = move.CheckTop; + CheckBottom = move.CheckBottom; + SpeedX = move.SpeedX; + SpeedY = move.SpeedY; + LocateLength = move.LocateLength; + TriggerLeft = move.TriggerLeft; + TriggerRight = move.TriggerRight; + TriggerTop = move.TriggerTop; + TriggerBottom = move.TriggerBottom; + LocateType.Value = move.LocateType; + TriggerType.Value = move.TriggerType; + ModeType.Value = move.Mode; + } + /// /// 移动类型 /// - public static ObservableCollection DirectionTypes { get; } = - new( - Enum.GetValues(typeof(GraphHelper.Move.DirectionType)) - .Cast() - ); + public static FrozenSet DirectionTypes { get; } = + Enum.GetValues().ToFrozenSet(); /// /// 模式类型 /// - public static ObservableCollection ModeTypes { get; } = - new(Enum.GetValues(typeof(GraphHelper.Move.ModeType)).Cast()); + public static FrozenSet ModeTypes { get; } = + Enum.GetValues().ToFrozenSet(); //#region Id //[DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -38,7 +84,7 @@ public class MoveModel : ObservableObjectX //#endregion #region Graph [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _graph; + private string _graph = string.Empty; /// /// 指定动画 @@ -255,54 +301,6 @@ public class MoveModel : ObservableObjectX | GraphHelper.Move.ModeType.Ill ); - public MoveModel() { } - - public MoveModel(MoveModel model) - : this() - { - //Id.EnumValue = model.Id.EnumValue; - Graph = model.Graph; - Distance = model.Distance; - Interval = model.Interval; - CheckLeft = model.CheckLeft; - CheckRight = model.CheckRight; - CheckTop = model.CheckTop; - CheckBottom = model.CheckBottom; - SpeedX = model.SpeedX; - SpeedY = model.SpeedY; - LocateLength = model.LocateLength; - TriggerLeft = model.TriggerLeft; - TriggerRight = model.TriggerRight; - TriggerTop = model.TriggerTop; - TriggerBottom = model.TriggerBottom; - LocateType.Value = model.LocateType.Value; - TriggerType.Value = model.TriggerType.Value; - ModeType.Value = model.ModeType.Value; - } - - public MoveModel(GraphHelper.Move move) - : this() - { - //Id.EnumValue = move.Id.EnumValue; - Graph = move.Graph; - Distance = move.Distance; - Interval = move.Interval; - CheckLeft = move.CheckLeft; - CheckRight = move.CheckRight; - CheckTop = move.CheckTop; - CheckBottom = move.CheckBottom; - SpeedX = move.SpeedX; - SpeedY = move.SpeedY; - LocateLength = move.LocateLength; - TriggerLeft = move.TriggerLeft; - TriggerRight = move.TriggerRight; - TriggerTop = move.TriggerTop; - TriggerBottom = move.TriggerBottom; - LocateType.Value = move.LocateType; - TriggerType.Value = move.TriggerType; - ModeType.Value = move.Mode; - } - public GraphHelper.Move ToMove() { return new() diff --git a/VPet.ModMaker/Models/ModModel/PetModel.cs b/VPet.ModMaker/Models/ModModel/PetModel.cs index a2bd53e..3b45482 100644 --- a/VPet.ModMaker/Models/ModModel/PetModel.cs +++ b/VPet.ModMaker/Models/ModModel/PetModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -13,6 +14,7 @@ using HKW.HKWUtils.Observable; using LinePutScript; using LinePutScript.Converter; using LinePutScript.Localization.WPF; +using Mapster; using VPet.ModMaker.Models.ModModel; using VPet_Simulator.Core; @@ -23,189 +25,38 @@ namespace VPet.ModMaker.Models; /// public class PetModel : I18nModel { - public static PetModel Default { get; } = new(); - - #region FromMain - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool _fromMain; - - /// - /// 来自本体 - /// - public bool FromMain - { - get => _fromMain; - set => SetProperty(ref _fromMain, value); - } - #endregion - - #region Id - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _id; - - /// - /// Id - /// - public string ID - { - get => _id; - set => SetProperty(ref _id, value); - } - #endregion - #region PetNameId - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _petNameId; - - /// - /// 名称Id - /// - public string PetNameId - { - get => _petNameId; - set => SetProperty(ref _petNameId, value); - } - #endregion - - #region DescriptionId - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _descriptionId; - - /// - /// 描述Id - /// - public string DescriptionId - { - get => _descriptionId; - set => SetProperty(ref _descriptionId, value); - } - #endregion - - #region TouchHeadRect - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableRectangleLocation _touchHeadRect = new(159, 16, 189, 178); - - /// - /// 头部点击区域 - /// - public ObservableRectangleLocation TouchHeadRect - { - get => _touchHeadRect; - set => SetProperty(ref _touchHeadRect, value); - } - #endregion - - #region TouchBodyRect - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableRectangleLocation _touchBodyRect = new(166, 206, 163, 136); - - /// - /// 身体区域 - /// - public ObservableRectangleLocation TouchBodyRect - { - get => _touchBodyRect; - set => SetProperty(ref _touchBodyRect, value); - } - #endregion - - /// - /// 提起区域 - /// - #region TouchRaisedRect - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableMultiStateRect _touchRaisedRect = - new( - new(0, 50, 500, 200), - new(0, 50, 500, 200), - new(0, 50, 500, 200), - new(0, 200, 500, 300) - ); - - public ObservableMultiStateRect TouchRaisedRect - { - get => _touchRaisedRect; - set => SetProperty(ref _touchRaisedRect, value); - } - #endregion - - #region RaisePoint - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableMultiStatePoint _raisePoint = - new(new(290, 128), new(290, 128), new(290, 128), new(225, 115)); - - /// - /// 提起定位 - /// - public ObservableMultiStatePoint RaisePoint - { - get => _raisePoint; - set => SetProperty(ref _raisePoint, value); - } - #endregion - - /// - /// 工作 - /// - public ObservableCollection Works { get; } = new(); - - /// - /// 移动 - /// - public ObservableCollection Moves { get; } = new(); - - /// - /// 动画 - /// - public ObservableCollection Animes { get; } = new(); - - /// - ///食物动画 - /// - public ObservableCollection FoodAnimes { get; } = new(); - - #region AnimeCount - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int _AnimeCount; - - public int AnimeCount - { - get => _AnimeCount; - set => SetProperty(ref _AnimeCount, value); - } - #endregion - public PetModel() { - PetNameId = $"{ID}_{nameof(PetNameId)}"; - DescriptionId = $"{ID}_{nameof(DescriptionId)}"; - //TODO - //ID.ValueChanged += (s, e) => - //{ - // PetNameId = $"{e.NewValue}_{nameof(PetNameId)}"; - // DescriptionId = $"{e.NewValue}_{nameof(DescriptionId)}"; - //}; - //AnimeCount.AddNotifySender(Animes); - //AnimeCount.AddNotifySender(FoodAnimes); - //AnimeCount.SenderPropertyChanged += (s, _) => - //{ - // s.Value = Animes.Count + FoodAnimes.Count; - //}; + PropertyChanged += PetModel_PropertyChanged; + Animes.PropertyChanged += Animes_PropertyChanged; + FoodAnimes.PropertyChanged += FoodAnimes_PropertyChanged; + } + + private void PetModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ID)) + { + PetNameID = $"{ID}_{nameof(PetNameID)}"; + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; + } } public PetModel(PetModel model) : this() { ID = model.ID; - PetNameId = model.PetNameId; - TouchHeadRect = model.TouchHeadRect.Clone(); - TouchBodyRect = model.TouchBodyRect.Clone(); - TouchRaisedRect = model.TouchRaisedRect.Copy(); - RaisePoint = model.RaisePoint.Copy(); + PetNameID = model.PetNameID; + DescriptionID = model.DescriptionID; + Tags = model.Tags; + TouchHeadRectangleLocation = model.TouchHeadRectangleLocation.Clone(); + TouchBodyRectangleLocation = model.TouchBodyRectangleLocation.Clone(); + TouchRaisedRectangleLocation = model.TouchRaisedRectangleLocation.Clone(); + RaisePoint = model.RaisePoint.Clone(); foreach (var work in model.Works) Works.Add(work); foreach (var item in model.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); + I18nDatas[item.Key] = item.Value.Clone(); CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; } @@ -213,42 +64,43 @@ public class PetModel : I18nModel : this() { ID = loader.Name; - PetNameId = loader.PetName; - DescriptionId = loader.Intor; + PetNameID = loader.PetName; + DescriptionID = loader.Intor; + Tags = loader.Config.Data["tag"].Info; - TouchHeadRect = new( + TouchHeadRectangleLocation = new( loader.Config.TouchHeadLocate.X, loader.Config.TouchHeadLocate.Y, loader.Config.TouchHeadSize.Width, loader.Config.TouchHeadSize.Height ); - TouchBodyRect = new( + TouchBodyRectangleLocation = new( loader.Config.TouchBodyLocate.X, loader.Config.TouchBodyLocate.Y, loader.Config.TouchBodySize.Width, loader.Config.TouchBodySize.Height ); - TouchRaisedRect.Happy = new( + TouchRaisedRectangleLocation.Happy = new( loader.Config.TouchRaisedLocate[0].X, loader.Config.TouchRaisedLocate[0].Y, loader.Config.TouchRaisedSize[0].Width, loader.Config.TouchRaisedSize[0].Height ); - TouchRaisedRect.Nomal = new( + TouchRaisedRectangleLocation.Nomal = new( loader.Config.TouchRaisedLocate[1].X, loader.Config.TouchRaisedLocate[1].Y, loader.Config.TouchRaisedSize[1].Width, loader.Config.TouchRaisedSize[1].Height ); - TouchRaisedRect.PoorCondition = new( + TouchRaisedRectangleLocation.PoorCondition = new( loader.Config.TouchRaisedLocate[2].X, loader.Config.TouchRaisedLocate[2].Y, loader.Config.TouchRaisedSize[2].Width, loader.Config.TouchRaisedSize[2].Height ); - TouchRaisedRect.Ill = new( + TouchRaisedRectangleLocation.Ill = new( loader.Config.TouchRaisedLocate[3].X, loader.Config.TouchRaisedLocate[3].Y, loader.Config.TouchRaisedSize[3].Width, @@ -272,10 +124,191 @@ public class PetModel : I18nModel Moves.Add(new(move)); } - public void RefreshId() + public static PetModel Current { get; } = new(); + + #region FromMain + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool _fromMain; + + /// + /// 来自本体 + /// + public bool FromMain { - PetNameId = $"{ID}_{nameof(PetNameId)}"; - DescriptionId = $"{ID}_{nameof(DescriptionId)}"; + get => _fromMain; + set => SetProperty(ref _fromMain, value); + } + #endregion + + #region ID + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _id = string.Empty; + + /// + /// Id + /// + public string ID + { + get => _id; + set + { + SetProperty(ref _id, value); + RefreshID(); + } + } + #endregion + #region PetNameId + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _petNameID = string.Empty; + + /// + /// 名称Id + /// + public string PetNameID + { + get => _petNameID; + set => SetProperty(ref _petNameID, value); + } + #endregion + + #region DescriptionId + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _descriptionID = string.Empty; + + /// + /// 描述Id + /// + public string DescriptionID + { + get => _descriptionID; + set => SetProperty(ref _descriptionID, value); + } + #endregion + + #region Tags + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _tags = string.Empty; + + /// + /// 标签 + /// + public string Tags + { + get => _tags; + set => SetProperty(ref _tags, value); + } + #endregion + + + #region TouchHeadRect + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableRectangleLocation _touchHeadRectangleLocation = + new(159, 16, 189, 178); + + /// + /// 头部点击区域 + /// + public ObservableRectangleLocation TouchHeadRectangleLocation + { + get => _touchHeadRectangleLocation; + set => SetProperty(ref _touchHeadRectangleLocation, value); + } + #endregion + + #region TouchBodyRect + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableRectangleLocation _touchBodyRectangleLocation = + new(166, 206, 163, 136); + + /// + /// 身体区域 + /// + public ObservableRectangleLocation TouchBodyRectangleLocation + { + get => _touchBodyRectangleLocation; + set => SetProperty(ref _touchBodyRectangleLocation, value); + } + #endregion + + /// + /// 提起区域 + /// + #region TouchRaisedRect + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableMultiStateRectangleLocation _touchRaisedRectangleLocation = + new( + new(0, 50, 500, 200), + new(0, 50, 500, 200), + new(0, 50, 500, 200), + new(0, 200, 500, 300) + ); + + public ObservableMultiStateRectangleLocation TouchRaisedRectangleLocation + { + get => _touchRaisedRectangleLocation; + set => SetProperty(ref _touchRaisedRectangleLocation, value); + } + #endregion + + #region RaisePoint + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableMultiStatePoint _raisePoint = + new(new(290, 128), new(290, 128), new(290, 128), new(225, 115)); + + /// + /// 提起定位 + /// + public ObservableMultiStatePoint RaisePoint + { + get => _raisePoint; + set => SetProperty(ref _raisePoint, value); + } + #endregion + + /// + /// 工作 + /// + public ObservableList Works { get; } = new(); + + /// + /// 移动 + /// + public ObservableList Moves { get; } = new(); + + /// + /// 动画 + /// + public ObservableList Animes { get; } = new(); + + /// + ///食物动画 + /// + public ObservableList FoodAnimes { get; } = new(); + + #region AnimeCount + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int _animeCount; + + public int AnimeCount + { + get => _animeCount; + set => SetProperty(ref _animeCount, value); + } + #endregion + private void FoodAnimes_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + AnimeCount = Animes.Count + FoodAnimes.Count; + } + + private void Animes_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + AnimeCount = Animes.Count + FoodAnimes.Count; + } + + public void RefreshID() + { + PetNameID = $"{ID}_{nameof(PetNameID)}"; + DescriptionID = $"{ID}_{nameof(DescriptionID)}"; } public void Close() @@ -316,10 +349,10 @@ public class PetModel : I18nModel ModInfoModel.SaveI18nDatas[cultureName].TryAdd(ID, I18nDatas[cultureName].Name); ModInfoModel .SaveI18nDatas[cultureName] - .TryAdd(PetNameId, I18nDatas[cultureName].PetName); + .TryAdd(PetNameID, I18nDatas[cultureName].PetName); ModInfoModel .SaveI18nDatas[cultureName] - .TryAdd(DescriptionId, I18nDatas[cultureName].Description); + .TryAdd(DescriptionID, I18nDatas[cultureName].Description); } var petFile = Path.Combine(path, $"{ID}.lps"); if (File.Exists(petFile) is false) @@ -351,7 +384,6 @@ public class PetModel : I18nModel /// 保存移动信息 /// /// - /// void SaveMoveInfo(LPS lps) { foreach (var move in Moves) @@ -364,7 +396,6 @@ public class PetModel : I18nModel /// 保存工作信息 /// /// - /// void SaveWorksInfo(LPS lps) { foreach (var work in Works) @@ -374,7 +405,7 @@ public class PetModel : I18nModel { ModInfoModel .SaveI18nDatas[cultureName] - .TryAdd(work.Id, work.I18nDatas[cultureName].Name); + .TryAdd(work.ID, work.I18nDatas[cultureName].Name); } } } @@ -405,16 +436,22 @@ public class PetModel : I18nModel { SavePetBasicInfo(lps); // 如果值不为默认并且不与本体值相同, 则保存 - if (TouchHeadRect != Default.TouchHeadRect && TouchHeadRect != mainPet.TouchHeadRect) + if ( + TouchHeadRectangleLocation != Current.TouchHeadRectangleLocation + && TouchHeadRectangleLocation != mainPet.TouchHeadRectangleLocation + ) SavePetTouchHeadInfo(lps); - if (TouchBodyRect != Default.TouchBodyRect && TouchBodyRect != mainPet.TouchBodyRect) + if ( + TouchBodyRectangleLocation != Current.TouchBodyRectangleLocation + && TouchBodyRectangleLocation != mainPet.TouchBodyRectangleLocation + ) SavePetTouchBodyInfo(lps); if ( - TouchRaisedRect != Default.TouchRaisedRect - && TouchRaisedRect != mainPet.TouchRaisedRect + TouchRaisedRectangleLocation != Current.TouchRaisedRectangleLocation + && TouchRaisedRectangleLocation != mainPet.TouchRaisedRectangleLocation ) SavePetTouchRaisedInfo(lps); - if (RaisePoint != Default.RaisePoint && RaisePoint != mainPet.RaisePoint) + if (RaisePoint != Current.RaisePoint && RaisePoint != mainPet.RaisePoint) SavePetRaisePointInfo(lps); } @@ -423,11 +460,12 @@ public class PetModel : I18nModel lps.Add( new Line("pet", ID) { - new Sub("intor", DescriptionId), + new Sub("intor", DescriptionID), new Sub("path", ID), - new Sub("petname", PetNameId) + new Sub("petname", PetNameID) } ); + lps.Add(new Line("tag", Tags)); } private void SavePetTouchHeadInfo(LPS lps) @@ -435,10 +473,10 @@ public class PetModel : I18nModel lps.Add( new Line("touchhead") { - new Sub("px", TouchHeadRect.X), - new Sub("py", TouchHeadRect.Y), - new Sub("sw", TouchHeadRect.Width), - new Sub("sh", TouchHeadRect.Height), + new Sub("px", TouchHeadRectangleLocation.X), + new Sub("py", TouchHeadRectangleLocation.Y), + new Sub("sw", TouchHeadRectangleLocation.Width), + new Sub("sh", TouchHeadRectangleLocation.Height), } ); } @@ -448,10 +486,10 @@ public class PetModel : I18nModel lps.Add( new Line("touchbody") { - new Sub("px", TouchBodyRect.X), - new Sub("py", TouchBodyRect.Y), - new Sub("sw", TouchBodyRect.Width), - new Sub("sh", TouchBodyRect.Height), + new Sub("px", TouchBodyRectangleLocation.X), + new Sub("py", TouchBodyRectangleLocation.Y), + new Sub("sw", TouchBodyRectangleLocation.Width), + new Sub("sh", TouchBodyRectangleLocation.Height), } ); } @@ -461,25 +499,25 @@ public class PetModel : I18nModel lps.Add( new Line("touchraised") { - new Sub("happy_px", TouchRaisedRect.Happy.X), - new Sub("happy_py", TouchRaisedRect.Happy.Y), - new Sub("happy_sw", TouchRaisedRect.Happy.Width), - new Sub("happy_sh", TouchRaisedRect.Happy.Height), + new Sub("happy_px", TouchRaisedRectangleLocation.Happy.X), + new Sub("happy_py", TouchRaisedRectangleLocation.Happy.Y), + new Sub("happy_sw", TouchRaisedRectangleLocation.Happy.Width), + new Sub("happy_sh", TouchRaisedRectangleLocation.Happy.Height), // - new Sub("nomal_px", TouchRaisedRect.Nomal.X), - new Sub("nomal_py", TouchRaisedRect.Nomal.Y), - new Sub("nomal_sw", TouchRaisedRect.Nomal.Width), - new Sub("nomal_sh", TouchRaisedRect.Nomal.Height), + new Sub("nomal_px", TouchRaisedRectangleLocation.Nomal.X), + new Sub("nomal_py", TouchRaisedRectangleLocation.Nomal.Y), + new Sub("nomal_sw", TouchRaisedRectangleLocation.Nomal.Width), + new Sub("nomal_sh", TouchRaisedRectangleLocation.Nomal.Height), // - new Sub("poorcondition_px", TouchRaisedRect.PoorCondition.X), - new Sub("poorcondition_py", TouchRaisedRect.PoorCondition.Y), - new Sub("poorcondition_sw", TouchRaisedRect.PoorCondition.Width), - new Sub("poorcondition_sh", TouchRaisedRect.PoorCondition.Height), + new Sub("poorcondition_px", TouchRaisedRectangleLocation.PoorCondition.X), + new Sub("poorcondition_py", TouchRaisedRectangleLocation.PoorCondition.Y), + new Sub("poorcondition_sw", TouchRaisedRectangleLocation.PoorCondition.Width), + new Sub("poorcondition_sh", TouchRaisedRectangleLocation.PoorCondition.Height), // - new Sub("ill_px", TouchRaisedRect.Ill.X), - new Sub("ill_py", TouchRaisedRect.Ill.Y), - new Sub("ill_sw", TouchRaisedRect.Ill.Width), - new Sub("ill_sh", TouchRaisedRect.Ill.Height), + new Sub("ill_px", TouchRaisedRectangleLocation.Ill.X), + new Sub("ill_py", TouchRaisedRectangleLocation.Ill.Y), + new Sub("ill_sw", TouchRaisedRectangleLocation.Ill.Width), + new Sub("ill_sh", TouchRaisedRectangleLocation.Ill.Height), } ); } @@ -507,7 +545,7 @@ public class PetModel : I18nModel #endregion } -public class I18nPetInfoModel : ObservableObjectX +public class I18nPetInfoModel : ObservableObjectX, ICloneable { #region Name [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -540,7 +578,7 @@ public class I18nPetInfoModel : ObservableObjectX } #endregion - public I18nPetInfoModel Copy() + public I18nPetInfoModel Clone() { var result = new I18nPetInfoModel(); result.Name = Name; @@ -548,15 +586,18 @@ public class I18nPetInfoModel : ObservableObjectX result.Description = Description; return result; } + + object ICloneable.Clone() => Clone(); } -public class ObservableMultiStateRect - : ObservableObjectX, - IEquatable +public class ObservableMultiStateRectangleLocation + : ObservableObjectX, + IEquatable, + ICloneable { #region Happy [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableRectangleLocation _happy; + private ObservableRectangleLocation _happy = null!; public ObservableRectangleLocation Happy { get => _happy; @@ -565,9 +606,9 @@ public class ObservableMultiStateRect #endregion #region Nomal - private ObservableRectangleLocation _nomal; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableRectangleLocation _nomal = null!; + public ObservableRectangleLocation Nomal { get => _nomal; @@ -577,7 +618,7 @@ public class ObservableMultiStateRect #region PoorCondition [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableRectangleLocation _poorCondition; + private ObservableRectangleLocation _poorCondition = null!; public ObservableRectangleLocation PoorCondition { get => _poorCondition; @@ -587,7 +628,7 @@ public class ObservableMultiStateRect #region Ill [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableRectangleLocation _ill; + private ObservableRectangleLocation _ill = null!; public ObservableRectangleLocation Ill { get => _ill; @@ -595,7 +636,7 @@ public class ObservableMultiStateRect } #endregion - public ObservableMultiStateRect() + public ObservableMultiStateRectangleLocation() { Happy = new(); Nomal = new(); @@ -603,7 +644,7 @@ public class ObservableMultiStateRect Ill = new(); } - public ObservableMultiStateRect( + public ObservableMultiStateRectangleLocation( ObservableRectangleLocation happy, ObservableRectangleLocation nomal, ObservableRectangleLocation poorCondition, @@ -616,7 +657,7 @@ public class ObservableMultiStateRect Ill = ill; } - public ObservableMultiStateRect Copy() + public ObservableMultiStateRectangleLocation Clone() { return new() { @@ -627,6 +668,8 @@ public class ObservableMultiStateRect }; } + object ICloneable.Clone() => Clone(); + #region Other /// @@ -638,36 +681,32 @@ public class ObservableMultiStateRect /// public override bool Equals(object? obj) { - return obj is ObservableMultiStateRect temp - && EqualityComparer>.Default.Equals( - Happy, - temp.Happy - ) - && EqualityComparer>.Default.Equals( - Nomal, - temp.Nomal - ) - && EqualityComparer>.Default.Equals( - PoorCondition, - temp.PoorCondition - ) - && EqualityComparer>.Default.Equals(Ill, temp.Ill); + return Equals(obj as ObservableMultiStateRectangleLocation); } /// - public bool Equals(ObservableMultiStateRect? other) + public bool Equals(ObservableMultiStateRectangleLocation? other) { - return Equals(obj: other); + return Happy.Equals(other?.Happy) + && Nomal.Equals(other?.Nomal) + && PoorCondition.Equals(other?.PoorCondition) + && Ill.Equals(other?.Ill); } /// - public static bool operator ==(ObservableMultiStateRect a, ObservableMultiStateRect b) + public static bool operator ==( + ObservableMultiStateRectangleLocation a, + ObservableMultiStateRectangleLocation b + ) { return Equals(a, b); } /// - public static bool operator !=(ObservableMultiStateRect a, ObservableMultiStateRect b) + public static bool operator !=( + ObservableMultiStateRectangleLocation a, + ObservableMultiStateRectangleLocation b + ) { return Equals(a, b) is not true; } @@ -677,11 +716,12 @@ public class ObservableMultiStateRect public class ObservableMultiStatePoint : ObservableObjectX, - IEquatable + IEquatable, + ICloneable { #region Happy [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservablePoint _happy; + private ObservablePoint _happy = null!; public ObservablePoint Happy { get => _happy; @@ -691,7 +731,7 @@ public class ObservableMultiStatePoint #region Nomal [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservablePoint _nomal; + private ObservablePoint _nomal = null!; public ObservablePoint Nomal { get => _nomal; @@ -701,7 +741,7 @@ public class ObservableMultiStatePoint #region PoorCondition [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservablePoint _poorCondition; + private ObservablePoint _poorCondition = null!; public ObservablePoint PoorCondition { get => _poorCondition; @@ -711,7 +751,7 @@ public class ObservableMultiStatePoint #region Ill [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservablePoint _ill; + private ObservablePoint _ill = null!; public ObservablePoint Ill { get => _ill; @@ -739,7 +779,7 @@ public class ObservableMultiStatePoint Ill = ill; } - public ObservableMultiStatePoint Copy() + public ObservableMultiStatePoint Clone() { return new() { @@ -750,6 +790,8 @@ public class ObservableMultiStatePoint }; } + object ICloneable.Clone() => Clone(); + #region Other /// @@ -761,20 +803,16 @@ public class ObservableMultiStatePoint /// public override bool Equals(object? obj) { - return obj is ObservableMultiStatePoint temp - && EqualityComparer>.Default.Equals(Happy, temp.Happy) - && EqualityComparer>.Default.Equals(Nomal, temp.Nomal) - && EqualityComparer>.Default.Equals( - PoorCondition, - temp.PoorCondition - ) - && EqualityComparer>.Default.Equals(Ill, temp.Ill); + return Equals(obj as ObservableMultiStatePoint); } /// public bool Equals(ObservableMultiStatePoint? other) { - return Equals(obj: other); + return Happy.Equals(other?.Happy) + && Nomal.Equals(other?.Nomal) + && PoorCondition.Equals(other?.PoorCondition) + && Ill.Equals(other?.Ill); } /// diff --git a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs index 4a59ff0..db9f108 100644 --- a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs @@ -119,7 +119,6 @@ public class SelectTextModel : I18nModel /// /// 选择Id /// - public string ChooseID { get => _chooseId; diff --git a/VPet.ModMaker/Models/ModModel/WorkModel.cs b/VPet.ModMaker/Models/ModModel/WorkModel.cs index 1588714..04573ce 100644 --- a/VPet.ModMaker/Models/ModModel/WorkModel.cs +++ b/VPet.ModMaker/Models/ModModel/WorkModel.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; @@ -8,6 +10,8 @@ using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Media.Imaging; using HKW.HKWUtils.Observable; +using Mapster; +using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.Models; @@ -16,23 +20,105 @@ namespace VPet.ModMaker.Models; /// public class WorkModel : I18nModel { + public WorkModel() + { + PropertyChanged += WorkModel_PropertyChanged; + } + + private static readonly FrozenSet _notifyIsOverLoad = FrozenSet.ToFrozenSet( + [ + nameof(WorkType), + nameof(MoneyBase), + nameof(StrengthFood), + nameof(StrengthDrink), + nameof(Feeling), + nameof(Feeling), + nameof(LevelLimit), + nameof(FinishBonus) + ] + ); + + private void WorkModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName is not null && _notifyIsOverLoad.Contains(e.PropertyName)) + { + IsOverLoad = VPet_Simulator.Windows.Interface.ExtensionFunction.IsOverLoad(ToWork()); + } + } + + public WorkModel(WorkModel model) + : this() + { + WorkType = model.WorkType; + ID = model.ID; + Graph = model.Graph; + //MoneyLevel = model.MoneyLevel; + MoneyBase = model.MoneyBase; + StrengthFood = model.StrengthFood; + StrengthDrink = model.StrengthDrink; + Feeling = model.Feeling; + LevelLimit = model.LevelLimit; + Time = model.Time; + FinishBonus = model.FinishBonus; + + BorderBrush = model.BorderBrush; + Background = model.Background; + ButtonBackground = model.ButtonBackground; + ButtonForeground = model.ButtonForeground; + Foreground = model.Foreground; + Left = model.Left; + Top = model.Top; + Width = model.Width; + + //Image = model.Image?.CloneStream(); + foreach (var item in model.I18nDatas) + I18nDatas[item.Key] = item.Value.Clone(); + CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; + } + + public WorkModel(VPet_Simulator.Core.GraphHelper.Work work) + : this() + { + WorkType = work.Type; + ID = work.Name; + Graph = work.Graph; + //MoneyLevel = work.MoneyLevel; + MoneyBase = work.MoneyBase; + StrengthFood = work.StrengthFood; + StrengthDrink = work.StrengthDrink; + Feeling = work.Feeling; + LevelLimit = work.LevelLimit; + Time = work.Time; + FinishBonus = work.FinishBonus; + + BorderBrush = new((Color)ColorConverter.ConvertFromString("#FF" + work.BorderBrush)); + Background = new((Color)ColorConverter.ConvertFromString("#FF" + work.Background)); + Foreground = new((Color)ColorConverter.ConvertFromString("#FF" + work.Foreground)); + ButtonBackground = new( + (Color)ColorConverter.ConvertFromString("#AA" + work.ButtonBackground) + ); + ButtonForeground = new( + (Color)ColorConverter.ConvertFromString("#FF" + work.ButtonForeground) + ); + Left = work.Left; + Top = work.Top; + Width = work.Width; + } + /// /// 工作类型 /// - public static ObservableCollection WorkTypes { get; } = - new( - Enum.GetValues(typeof(VPet_Simulator.Core.GraphHelper.Work.WorkType)) - .Cast() - ); + public static FrozenSet WorkTypes { get; } = + Enum.GetValues().ToFrozenSet(); #region Id [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _id; + private string _id = string.Empty; /// /// Id /// - public string Id + public string ID { get => _id; set => SetProperty(ref _id, value); @@ -41,12 +127,11 @@ public class WorkModel : I18nModel #region Graph [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _graph; + private string _graph = string.Empty; /// /// 指定动画 /// - public string Graph { get => _graph; @@ -180,19 +265,19 @@ public class WorkModel : I18nModel } #endregion - #region Image - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _image; + //#region Image + //[DebuggerBrowsable(DebuggerBrowsableState.Never)] + //private BitmapImage? _image; - /// - /// 图片 - /// - public BitmapImage Image - { - get => _image; - set => SetProperty(ref _image, value); - } - #endregion + ///// + ///// 图片 + ///// + //public BitmapImage? Image + //{ + // get => _image; + // set => SetProperty(ref _image, value); + //} + //#endregion #region WorkType [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -224,13 +309,13 @@ public class WorkModel : I18nModel } #endregion - /// - /// 背景色 - /// #region Background [DebuggerBrowsable(DebuggerBrowsableState.Never)] private SolidColorBrush _background = new((Color)ColorConverter.ConvertFromString("#FF81D4FA")); + /// + /// 背景色 + /// public SolidColorBrush Background { get => _background; @@ -238,13 +323,13 @@ public class WorkModel : I18nModel } #endregion - /// - /// 前景色 - /// #region Foreground [DebuggerBrowsable(DebuggerBrowsableState.Never)] private SolidColorBrush _foreground = new((Color)ColorConverter.ConvertFromString("#FF0286C6")); + /// + /// 前景色 + /// public SolidColorBrush Foreground { get => _foreground; @@ -252,14 +337,14 @@ public class WorkModel : I18nModel } #endregion - /// - /// 按钮背景色 - /// #region ButtonBackground [DebuggerBrowsable(DebuggerBrowsableState.Never)] private SolidColorBrush _buttonBackground = new((Color)ColorConverter.ConvertFromString("#AA0286C6")); + /// + /// 按钮背景色 + /// public SolidColorBrush ButtonBackground { get => _buttonBackground; @@ -267,135 +352,67 @@ public class WorkModel : I18nModel } #endregion + #region ButtonForeground + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SolidColorBrush _buttonForeground = + new((Color)ColorConverter.ConvertFromString("#FFFFFFFF")); + /// /// 按钮前景色 /// - #region ButtonForeground - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private SolidColorBrush _buttonForeground; - public SolidColorBrush ButtonForeground { get => _buttonForeground; set => SetProperty(ref _buttonForeground, value); } #endregion + #region Left + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _left; + /// /// X位置 /// - #region Left - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Left; - public double Left { - get => _Left; - set => SetProperty(ref _Left, value); + get => _left; + set => SetProperty(ref _left, value); } #endregion + #region Top + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _top; + /// /// Y位置 /// - #region Top - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Top; - public double Top { - get => _Top; - set => SetProperty(ref _Top, value); + get => _top; + set => SetProperty(ref _top, value); } #endregion + #region Width + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private double _width; + /// /// 宽度 /// - #region Width - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _Width; - public double Width { - get => _Width; - set => SetProperty(ref _Width, value); + get => _width; + set => SetProperty(ref _width, value); } #endregion - public WorkModel() - { //TODO - //IsOverLoad.AddNotifySender( - // WorkType, - // MoneyBase, - // //MoneyLevel, - // StrengthFood, - // StrengthDrink, - // Feeling, - // LevelLimit, - // FinishBonus - //); - //IsOverLoad.SenderPropertyChanged += (s, _) => - //{ - // s.Value = VPet_Simulator.Windows.Interface.ExtensionFunction.IsOverLoad(ToWork()); - //}; - } - - public WorkModel(WorkModel model) - : this() + public void FixOverLoad() { - WorkType = model.WorkType; - Id = model.Id; - Graph = model.Graph; - //MoneyLevel = model.MoneyLevel; - MoneyBase = model.MoneyBase; - StrengthFood = model.StrengthFood; - StrengthDrink = model.StrengthDrink; - Feeling = model.Feeling; - LevelLimit = model.LevelLimit; - Time = model.Time; - FinishBonus = model.FinishBonus; - - BorderBrush = model.BorderBrush; - Background = model.Background; - ButtonBackground = model.ButtonBackground; - ButtonForeground = model.ButtonForeground; - Foreground = model.Foreground; - Left = model.Left; - Top = model.Top; - Width = model.Width; - - foreach (var item in model.I18nDatas) - I18nDatas[item.Key] = item.Value.Copy(); - CurrentI18nData = I18nDatas[I18nHelper.Current.CultureName]; - } - - public WorkModel(VPet_Simulator.Core.GraphHelper.Work work) - : this() - { - WorkType = work.Type; - Id = work.Name; - Graph = work.Graph; - //MoneyLevel = work.MoneyLevel; - MoneyBase = work.MoneyBase; - StrengthFood = work.StrengthFood; - StrengthDrink = work.StrengthDrink; - Feeling = work.Feeling; - LevelLimit = work.LevelLimit; - Time = work.Time; - FinishBonus = work.FinishBonus; - - BorderBrush = new((Color)ColorConverter.ConvertFromString("#FF" + work.BorderBrush)); - Background = new((Color)ColorConverter.ConvertFromString("#FF" + work.Background)); - Foreground = new((Color)ColorConverter.ConvertFromString("#FF" + work.Foreground)); - ButtonBackground = new( - (Color)ColorConverter.ConvertFromString("#AA" + work.ButtonBackground) - ); - ButtonForeground = new( - (Color)ColorConverter.ConvertFromString("#FF" + work.ButtonForeground) - ); - Left = work.Left; - Top = work.Top; - Width = work.Width; + var work = ToWork(); + work.FixOverLoad(); + work.Adapt(this); } public VPet_Simulator.Core.GraphHelper.Work ToWork() @@ -403,7 +420,7 @@ public class WorkModel : I18nModel return new() { Type = WorkType, - Name = Id, + Name = ID, Graph = Graph, //MoneyLevel = MoneyLevel, MoneyBase = MoneyBase, @@ -428,15 +445,15 @@ public class WorkModel : I18nModel public void Close() { - Image.CloseStream(); + //Image?.CloseStream(); } } -public class I18nWorkModel : ObservableObjectX +public class I18nWorkModel : ObservableObjectX, ICloneable { #region Name [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _name; + private string _name = string.Empty; public string Name { @@ -445,10 +462,12 @@ public class I18nWorkModel : ObservableObjectX } #endregion - public I18nWorkModel Copy() + public I18nWorkModel Clone() { var result = new I18nWorkModel(); result.Name = Name; return result; } + + object ICloneable.Clone() => Clone(); } diff --git a/VPet.ModMaker/Utils/NativeExtensions.cs b/VPet.ModMaker/Utils/NativeExtensions.cs index e5ce150..c8ff45d 100644 --- a/VPet.ModMaker/Utils/NativeExtensions.cs +++ b/VPet.ModMaker/Utils/NativeExtensions.cs @@ -285,6 +285,24 @@ public static class NativeExtensions catch { } }; } + + public static void SetDataContext( + this Window window, + object viewModel, + Action? closedAction = null + ) + { + window.DataContext = viewModel; + window.Closed += (s, e) => + { + try + { + closedAction?.Invoke(); + window.DataContext = null; + } + catch { } + }; + } } /// diff --git a/VPet.ModMaker/VPet.ModMaker.csproj b/VPet.ModMaker/VPet.ModMaker.csproj index 77f4fda..3feb1d7 100644 --- a/VPet.ModMaker/VPet.ModMaker.csproj +++ b/VPet.ModMaker/VPet.ModMaker.csproj @@ -27,7 +27,7 @@ - + diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs index 7bca428..7d34aac 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimeEditWindowVM.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -21,24 +22,70 @@ namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; public class AnimeEditWindowVM : ObservableObjectX { + public AnimeEditWindowVM() + { + _playerTask = new(Play); + PropertyChangedX += AnimeEditWindowVM_PropertyChangedX; + + PlayCommand.ExecuteAsyncCommand += PlayCommand_ExecuteAsyncCommand; + StopCommand.ExecuteCommand += StopCommand_ExecuteCommand; + AddAnimeCommand.ExecuteCommand += AddAnimeCommand_ExecuteCommand; + RemoveAnimeCommand.ExecuteCommand += RemoveAnimeCommand_ExecuteCommand; + AddImageCommand.ExecuteCommand += AddImageCommand_ExecuteCommand; + RemoveImageCommand.ExecuteCommand += RemoveImageCommand_ExecuteCommand; + ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; + ClearImageCommand.ExecuteCommand += ClearImageCommand_ExecuteCommand; + } + + private void AnimeEditWindowVM_PropertyChangedX( + AnimeEditWindowVM sender, + PropertyChangedXEventArgs e + ) + { + if (e.PropertyName == nameof(CurrentAnimeModel)) + { + var newModel = e.NewValue as AnimeModel; + var oldModel = e.OldValue as AnimeModel; + StopCommand_ExecuteCommand(); + if (oldModel is not null) + oldModel.Images.CollectionChanged -= Images_CollectionChanged; + if (newModel is not null) + newModel.Images.CollectionChanged += Images_CollectionChanged; + } + } + /// /// 当前宠物 /// - public PetModel CurrentPet { get; set; } + public PetModel CurrentPet { get; set; } = null!; /// /// 旧动画 /// - public AnimeTypeModel OldAnime { get; set; } + public AnimeTypeModel? OldAnime { get; set; } + + #region Anime + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private AnimeTypeModel _anime = new(); /// /// 动画 /// - public ObservableValue Anime { get; } = new(new()); + public AnimeTypeModel Anime + { + get => _anime; + set + { + if (SetProperty(ref _anime, value) is false) + return; + CheckGraphType(Anime); + } + } + #endregion #region CurrentImageModel [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ImageModel _currentImageModel; + private ImageModel _currentImageModel = null!; /// /// 当前图像模型 @@ -52,7 +99,7 @@ public class AnimeEditWindowVM : ObservableObjectX #region CurrentAnimeModel [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private AnimeModel _currentAnimeModel; + private AnimeModel _currentAnimeModel = null!; /// /// 当前动画模型 @@ -164,32 +211,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// private Task _playerTask; - public AnimeEditWindowVM() - { - _playerTask = new(Play); - //TODO - //CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged; - - PlayCommand.ExecuteAsyncCommand += PlayCommand_AsyncExecuteEvent; - StopCommand.ExecuteCommand += StopCommand_ExecuteEvent; - AddAnimeCommand.ExecuteCommand += AddAnimeCommand_ExecuteEvent; - RemoveAnimeCommand.ExecuteCommand += RemoveAnimeCommand_ExecuteEvent; - AddImageCommand.ExecuteCommand += AddImageCommand_ExecuteEvent; - RemoveImageCommand.ExecuteCommand += RemoveImageCommand_ExecuteEvent; - ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteEvent; - ClearImageCommand.ExecuteCommand += ClearImageCommand_ExecuteEvent; - - Anime.ValueChanged += Anime_ValueChanged; - } - #region LoadAnime - private void Anime_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - CheckGraphType(e.NewValue); - } private void CheckGraphType(AnimeTypeModel model) { @@ -206,16 +228,16 @@ public class AnimeEditWindowVM : ObservableObjectX /// 添加动画 /// /// 动画模型 - private void AddAnimeCommand_ExecuteEvent() + private void AddAnimeCommand_ExecuteCommand() { if (CurrentMode is ModeType.Happy) - Anime.Value.HappyAnimes.Add(new()); + Anime.HappyAnimes.Add(new()); else if (CurrentMode is ModeType.Nomal) - Anime.Value.NomalAnimes.Add(new()); + Anime.NomalAnimes.Add(new()); else if (CurrentMode is ModeType.PoorCondition) - Anime.Value.PoorConditionAnimes.Add(new()); + Anime.PoorConditionAnimes.Add(new()); else if (CurrentMode is ModeType.Ill) - Anime.Value.IllAnimes.Add(new()); + Anime.IllAnimes.Add(new()); } /// @@ -223,20 +245,20 @@ public class AnimeEditWindowVM : ObservableObjectX /// /// 动画模型 - private void RemoveAnimeCommand_ExecuteEvent(AnimeModel value) + private void RemoveAnimeCommand_ExecuteCommand(AnimeModel value) { if ( MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes ) { if (CurrentMode is ModeType.Happy) - Anime.Value.HappyAnimes.Remove(value); + Anime.HappyAnimes.Remove(value); else if (CurrentMode is ModeType.Nomal) - Anime.Value.NomalAnimes.Remove(value); + Anime.NomalAnimes.Remove(value); else if (CurrentMode is ModeType.PoorCondition) - Anime.Value.PoorConditionAnimes.Remove(value); + Anime.PoorConditionAnimes.Remove(value); else if (CurrentMode is ModeType.Ill) - Anime.Value.IllAnimes.Remove(value); + Anime.IllAnimes.Remove(value); value.Close(); } } @@ -248,7 +270,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// 添加图片 /// /// 动画模型 - private void AddImageCommand_ExecuteEvent(AnimeModel value) + private void AddImageCommand_ExecuteCommand(AnimeModel value) { OpenFileDialog openFileDialog = new() @@ -266,7 +288,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// 删除图片 /// /// 动画模型 - private void RemoveImageCommand_ExecuteEvent(AnimeModel value) + private void RemoveImageCommand_ExecuteCommand(AnimeModel value) { CurrentImageModel.Close(); value.Images.Remove(CurrentImageModel); @@ -277,7 +299,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// /// /// - private void ChangeImageCommand_ExecuteEvent(AnimeModel value) + private void ChangeImageCommand_ExecuteCommand(AnimeModel value) { OpenFileDialog openFileDialog = new() { Title = "选择图片".Translate(), Filter = $"图片|*.png".Translate() }; @@ -303,7 +325,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// 清空图片 /// /// 动画模型 - private void ClearImageCommand_ExecuteEvent(AnimeModel value) + private void ClearImageCommand_ExecuteCommand(AnimeModel value) { if ( MessageBox.Show("确定清空吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes @@ -319,7 +341,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// /// 动画 /// 路径 - public void AddImages(ObservableCollection images, IEnumerable paths) + public void AddImages(ObservableList images, IEnumerable paths) { try { @@ -348,27 +370,16 @@ public class AnimeEditWindowVM : ObservableObjectX } #endregion #region Player - private void CurrentAnimeModel_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - StopCommand_ExecuteEvent(); - if (e.OldValue is not null) - e.OldValue.Images.CollectionChanged -= Images_CollectionChanged; - if (e.NewValue is not null) - e.NewValue.Images.CollectionChanged += Images_CollectionChanged; - } - private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + private void Images_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { - StopCommand_ExecuteEvent(); + StopCommand_ExecuteCommand(); } /// /// 停止播放 /// - private void StopCommand_ExecuteEvent() + private void StopCommand_ExecuteCommand() { _playing = false; } @@ -376,7 +387,7 @@ public class AnimeEditWindowVM : ObservableObjectX /// /// 开始播放 /// - private async Task PlayCommand_AsyncExecuteEvent() + private async Task PlayCommand_ExecuteAsyncCommand() { if (CurrentAnimeModel is null) { @@ -385,7 +396,7 @@ public class AnimeEditWindowVM : ObservableObjectX } _playing = true; _playerTask.Start(); - await Task.WhenAll(_playerTask); + await _playerTask; Reset(); } diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs index f9472d5..051cdca 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/AnimePageVM.cs @@ -18,51 +18,94 @@ namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; public class AnimePageVM : ObservableObjectX { + public AnimePageVM() + { + AllAnimes = new() + { + Filter = (f) => + { + if (f is AnimeTypeModel animeModel) + { + return animeModel.ID.Contains(Search, StringComparison.OrdinalIgnoreCase); + } + else if (f is FoodAnimeTypeModel foodAnimeModel) + { + return foodAnimeModel.ID.Contains(Search, StringComparison.OrdinalIgnoreCase); + } + else + throw new Exception("???"); + }, + FilteredList = new() + }; + PropertyChangedX += AnimePageVM_PropertyChangedX; + + AddCommand.ExecuteCommand += AddCommand_ExecuteCommand; + EditCommand.ExecuteCommand += EditCommand_ExecuteCommand; + RemoveCommand.ExecuteCommand += RemoveCommand_ExecuteCommand; + } + + private void AnimePageVM_PropertyChangedX(AnimePageVM sender, PropertyChangedXEventArgs e) + { + if (e.PropertyName == nameof(CurrentPet)) + { + InitializeAllAnimes(); + } + else if (e.PropertyName == nameof(Search)) + { + AllAnimes.Refresh(); + } + } + public static ModInfoModel ModInfo => ModInfoModel.Current; - #region Value + #region Property /// - /// 显示的动画 + /// 所有动画 /// - #region ShowAnimes + #region AllAnimes [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableCollection _showAnimes; + private ObservableFilterList> _allAnimes = null!; - public ObservableCollection ShowAnimes + public ObservableFilterList> AllAnimes { - get => _showAnimes; - set => SetProperty(ref _showAnimes, value); + get => _allAnimes; + set => SetProperty(ref _allAnimes, value); } #endregion - /// - /// 所有动画 - /// - public ObservableCollection AllAnimes { get; } = new(); - /// /// 动画 /// - public ObservableCollection Animes => CurrentPet.Value.Animes; + public ObservableList Animes => CurrentPet.Animes; /// /// 食物动画 /// - public ObservableCollection FoodAnimes => CurrentPet.Value.FoodAnimes; + public ObservableList FoodAnimes => CurrentPet.FoodAnimes; /// /// 宠物列表 /// - public ObservableCollection Pets => ModInfoModel.Current.Pets; + public static ObservableList Pets => ModInfoModel.Current.Pets; + + #region CurrentPEt + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private PetModel _currentPet = null!; /// /// 当前宠物 /// - public ObservableValue CurrentPet { get; } = new(new()); + public PetModel CurrentPet + { + get => _currentPet; + set => SetProperty(ref _currentPet, value); + } + #endregion + #region Search [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _search; + private string _search = string.Empty; /// /// 搜索 @@ -90,18 +133,6 @@ public class AnimePageVM : ObservableObjectX /// public ObservableCommand RemoveCommand { get; } = new(); #endregion - public AnimePageVM() - { - ShowAnimes = AllAnimes; - CurrentPet.ValueChanged += CurrentPet_ValueChanged; - //TODO - //Search.ValueChanged += Search_ValueChanged; - - AddCommand.ExecuteCommand += Add; - EditCommand.ExecuteCommand += Edit; - RemoveCommand.ExecuteCommand += Remove; - } - private void InitializeAllAnimes() { AllAnimes.Clear(); @@ -109,70 +140,32 @@ public class AnimePageVM : ObservableObjectX AllAnimes.Add(item); foreach (var item in FoodAnimes) AllAnimes.Add(item); + Animes.CollectionChanged -= Animes_CollectionChanged; Animes.CollectionChanged += Animes_CollectionChanged; + FoodAnimes.CollectionChanged -= Animes_CollectionChanged; FoodAnimes.CollectionChanged += Animes_CollectionChanged; } - private void Animes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + private void Animes_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (e.Action is NotifyCollectionChangedAction.Add) - AllAnimes.Add(e.NewItems[0]); + AllAnimes.Add(e.NewItems![0]!); else if (e.Action is NotifyCollectionChangedAction.Remove) - AllAnimes.Remove(e.OldItems[0]); + AllAnimes.Remove(e.OldItems![0]!); else if (e.Action is NotifyCollectionChangedAction.Replace) - AllAnimes[AllAnimes.IndexOf(e.OldItems[0])] = e.NewItems[0]; - } - - private void CurrentPet_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - InitializeAllAnimes(); - ShowAnimes = AllAnimes; - } - - private void Search_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - if (string.IsNullOrWhiteSpace(e.NewValue)) - { - ShowAnimes = AllAnimes; - } - else - { - ShowAnimes = new( - AllAnimes.Where(m => - { - if (m is AnimeTypeModel animeTypeModel) - return animeTypeModel.Id.Contains( - e.NewValue, - StringComparison.OrdinalIgnoreCase - ); - else if (m is FoodAnimeTypeModel foodAnimeTypeModel) - return foodAnimeTypeModel.Id.Contains( - e.NewValue, - StringComparison.OrdinalIgnoreCase - ); - else - throw new Exception("???"); - }) - ); - } + AllAnimes[AllAnimes.IndexOf(e.OldItems![0]!)] = e.NewItems![0]!; } /// /// 添加动画 /// - private void Add() + private void AddCommand_ExecuteCommand() { var selectGraphTypeWindow = new SelectGraphTypeWindow(); - selectGraphTypeWindow.CurrentPet.Value = CurrentPet.Value; + selectGraphTypeWindow.ViewModel.CurrentPet = CurrentPet; selectGraphTypeWindow.ShowDialog(); - var graphType = selectGraphTypeWindow.GraphType.Value; - var animeName = selectGraphTypeWindow.AnimeName.Value; + var graphType = selectGraphTypeWindow.ViewModel.GraphType; + var animeName = selectGraphTypeWindow.ViewModel.AnimeName; if (selectGraphTypeWindow.IsCancel) return; if ( @@ -182,24 +175,24 @@ public class AnimePageVM : ObservableObjectX { var window = new FoodAnimeEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; - vm.Anime.Value.Name = animeName; + vm.CurrentPet = CurrentPet; + vm.Anime.Name = animeName; window.ShowDialog(); if (window.IsCancel) return; - FoodAnimes.Add(vm.Anime.Value); + FoodAnimes.Add(vm.Anime); } else { var window = new AnimeEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; - vm.Anime.Value.GraphType = graphType; - vm.Anime.Value.Name = animeName; + vm.CurrentPet = CurrentPet; + vm.Anime.GraphType = graphType; + vm.Anime.Name = animeName; window.ShowDialog(); if (window.IsCancel) return; - Animes.Add(vm.Anime.Value); + Animes.Add(vm.Anime); } } @@ -207,38 +200,34 @@ public class AnimePageVM : ObservableObjectX /// 编辑动画 /// /// 动画类型模型 - public void Edit(object model) + public void EditCommand_ExecuteCommand(object model) { var pendingHandler = PendingBox.Show("载入中".Translate()); if (model is AnimeTypeModel animeTypeModel) { var window = new AnimeEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; + vm.CurrentPet = CurrentPet; vm.OldAnime = animeTypeModel; - var newAnime = vm.Anime.Value = new(animeTypeModel); + var newAnime = vm.Anime = new(animeTypeModel); pendingHandler.Close(); window.ShowDialog(); if (window.IsCancel) return; Animes[Animes.IndexOf(animeTypeModel)] = newAnime; - if (ShowAnimes.Count != Animes.Count) - ShowAnimes[ShowAnimes.IndexOf(animeTypeModel)] = newAnime; } else if (model is FoodAnimeTypeModel foodAnimeTypeModel) { var window = new FoodAnimeEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; + vm.CurrentPet = CurrentPet; vm.OldAnime = foodAnimeTypeModel; - var newAnime = vm.Anime.Value = new(foodAnimeTypeModel); + var newAnime = vm.Anime = new(foodAnimeTypeModel); pendingHandler.Close(); window.ShowDialog(); if (window.IsCancel) return; FoodAnimes[FoodAnimes.IndexOf(foodAnimeTypeModel)] = newAnime; - if (ShowAnimes.Count != FoodAnimes.Count) - ShowAnimes[ShowAnimes.IndexOf(foodAnimeTypeModel)] = newAnime; } } @@ -246,11 +235,11 @@ public class AnimePageVM : ObservableObjectX /// 删除动画 /// /// 动画类型模型 - private void Remove(object model) + private void RemoveCommand_ExecuteCommand(object model) { if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No) return; - ShowAnimes.Remove(model); + AllAnimes.Remove(model); if (model is AnimeTypeModel animeTypeModel) { Animes.Remove(animeTypeModel); diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/FoodAnimeEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/FoodAnimeEditWindowVM.cs index eddba3c..146fea1 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/FoodAnimeEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/FoodAnimeEditWindowVM.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Threading.Tasks; @@ -20,6 +21,62 @@ namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; public class FoodAnimeEditWindowVM : ObservableObjectX { + public FoodAnimeEditWindowVM() + { + _frontPlayerTask = new(FrontPlay); + _backPlayerTask = new(BackPlay); + _foodPlayerTask = new(FoodPlay); + PropertyChangedX += FoodAnimeEditWindowVM_PropertyChangedX; + ; + + PlayCommand.ExecuteAsyncCommand += PlayCommand_AsyncExecuteEvent; + StopCommand.ExecuteCommand += StopCommand_ExecuteEvent; + ReplaceFoodImageCommand.ExecuteCommand += ChangeFoodImageCommand_ExecuteEvent; + ResetFoodImageCommand.ExecuteCommand += ResetFoodImageCommand_ExecuteEvent; + + AddAnimeCommand.ExecuteCommand += AddAnimeCommand_ExecuteEvent; + RemoveAnimeCommand.ExecuteCommand += RemoveAnimeCommand_ExecuteEvent; + + AddFrontImageCommand.ExecuteCommand += AddFrontImageCommand_ExecuteEvent; + RemoveFrontImageCommand.ExecuteCommand += RemoveFrontImageCommand_ExecuteEvent; + ClearFrontImageCommand.ExecuteCommand += ClearFrontImageCommand_ExecuteEvent; + ChangeFrontImageCommand.ExecuteCommand += ChangeFrontImageCommand_ExecuteEvent; + + AddBackImageCommand.ExecuteCommand += AddBackImageCommand_ExecuteEvent; + RemoveBackImageCommand.ExecuteCommand += RemoveBackImageCommand_ExecuteEvent; + ClearBackImageCommand.ExecuteCommand += ClearBackImageCommand_ExecuteEvent; + ChangeBackImageCommand.ExecuteCommand += ChangeBackImageCommand_ExecuteEvent; + + AddFoodLocationCommand.ExecuteCommand += AddeFoodLocationCommand_ExecuteEvent; + RemoveFoodLocationCommand.ExecuteCommand += RemoveFoodLocationCommand_ExecuteEvent; + ClearFoodLocationCommand.ExecuteCommand += ClearFoodLocationCommand_ExecuteEvent; + } + + private void FoodAnimeEditWindowVM_PropertyChangedX( + FoodAnimeEditWindowVM sender, + PropertyChangedXEventArgs e + ) + { + if (e.PropertyName == nameof(CurrentAnimeModel)) + { + var newModel = e.NewValue as FoodAnimeModel; + var oldModel = e.OldValue as FoodAnimeModel; + StopCommand_ExecuteEvent(); + if (oldModel is not null) + { + oldModel.FrontImages.CollectionChanged -= Images_CollectionChanged; + oldModel.BackImages.CollectionChanged -= Images_CollectionChanged; + oldModel.FoodLocations.CollectionChanged -= Images_CollectionChanged; + } + if (newModel is not null) + { + newModel.FrontImages.CollectionChanged += Images_CollectionChanged; + newModel.BackImages.CollectionChanged += Images_CollectionChanged; + newModel.FoodLocations.CollectionChanged += Images_CollectionChanged; + } + } + } + /// /// 当前宠物 /// @@ -67,7 +124,16 @@ public class FoodAnimeEditWindowVM : ObservableObjectX /// /// 动画 /// - public ObservableValue Anime { get; } = new(new()); + #region Anime + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private FoodAnimeTypeModel _anime = new(); + + public FoodAnimeTypeModel Anime + { + get => _anime; + set => SetProperty(ref _anime, value); + } + #endregion #region CurrentFrontImageModel [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -284,37 +350,6 @@ public class FoodAnimeEditWindowVM : ObservableObjectX /// private Task _foodPlayerTask; - public FoodAnimeEditWindowVM() - { - _frontPlayerTask = new(FrontPlay); - _backPlayerTask = new(BackPlay); - _foodPlayerTask = new(FoodPlay); - //TODO - //CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged; - - PlayCommand.ExecuteAsyncCommand += PlayCommand_AsyncExecuteEvent; - StopCommand.ExecuteCommand += StopCommand_ExecuteEvent; - ReplaceFoodImageCommand.ExecuteCommand += ChangeFoodImageCommand_ExecuteEvent; - ResetFoodImageCommand.ExecuteCommand += ResetFoodImageCommand_ExecuteEvent; - - AddAnimeCommand.ExecuteCommand += AddAnimeCommand_ExecuteEvent; - RemoveAnimeCommand.ExecuteCommand += RemoveAnimeCommand_ExecuteEvent; - - AddFrontImageCommand.ExecuteCommand += AddFrontImageCommand_ExecuteEvent; - RemoveFrontImageCommand.ExecuteCommand += RemoveFrontImageCommand_ExecuteEvent; - ClearFrontImageCommand.ExecuteCommand += ClearFrontImageCommand_ExecuteEvent; - ChangeFrontImageCommand.ExecuteCommand += ChangeFrontImageCommand_ExecuteEvent; - - AddBackImageCommand.ExecuteCommand += AddBackImageCommand_ExecuteEvent; - RemoveBackImageCommand.ExecuteCommand += RemoveBackImageCommand_ExecuteEvent; - ClearBackImageCommand.ExecuteCommand += ClearBackImageCommand_ExecuteEvent; - ChangeBackImageCommand.ExecuteCommand += ChangeBackImageCommand_ExecuteEvent; - - AddFoodLocationCommand.ExecuteCommand += AddeFoodLocationCommand_ExecuteEvent; - RemoveFoodLocationCommand.ExecuteCommand += RemoveFoodLocationCommand_ExecuteEvent; - ClearFoodLocationCommand.ExecuteCommand += ClearFoodLocationCommand_ExecuteEvent; - } - private void ResetFoodImageCommand_ExecuteEvent() { if (FoodImage != DefaultFoodImage) @@ -353,13 +388,13 @@ public class FoodAnimeEditWindowVM : ObservableObjectX private void AddAnimeCommand_ExecuteEvent() { if (CurrentMode is ModeType.Happy) - Anime.Value.HappyAnimes.Add(new()); + Anime.HappyAnimes.Add(new()); else if (CurrentMode is ModeType.Nomal) - Anime.Value.NomalAnimes.Add(new()); + Anime.NomalAnimes.Add(new()); else if (CurrentMode is ModeType.PoorCondition) - Anime.Value.PoorConditionAnimes.Add(new()); + Anime.PoorConditionAnimes.Add(new()); else if (CurrentMode is ModeType.Ill) - Anime.Value.IllAnimes.Add(new()); + Anime.IllAnimes.Add(new()); } /// @@ -374,13 +409,13 @@ public class FoodAnimeEditWindowVM : ObservableObjectX ) { if (CurrentMode is ModeType.Happy) - Anime.Value.HappyAnimes.Remove(value); + Anime.HappyAnimes.Remove(value); else if (CurrentMode is ModeType.Nomal) - Anime.Value.NomalAnimes.Remove(value); + Anime.NomalAnimes.Remove(value); else if (CurrentMode is ModeType.PoorCondition) - Anime.Value.PoorConditionAnimes.Remove(value); + Anime.PoorConditionAnimes.Remove(value); else if (CurrentMode is ModeType.Ill) - Anime.Value.IllAnimes.Remove(value); + Anime.IllAnimes.Remove(value); value.Close(); } } @@ -540,7 +575,7 @@ public class FoodAnimeEditWindowVM : ObservableObjectX /// /// 动画 /// 路径 - public void AddImages(ObservableCollection images, IEnumerable paths) + public void AddImages(ObservableList images, IEnumerable paths) { try { @@ -591,27 +626,8 @@ public class FoodAnimeEditWindowVM : ObservableObjectX } #endregion #region FrontPlayer - private void CurrentAnimeModel_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - StopCommand_ExecuteEvent(); - if (e.OldValue is not null) - { - e.OldValue.FrontImages.CollectionChanged -= Images_CollectionChanged; - e.OldValue.BackImages.CollectionChanged -= Images_CollectionChanged; - e.OldValue.FoodLocations.CollectionChanged -= Images_CollectionChanged; - } - if (e.NewValue is not null) - { - e.NewValue.FrontImages.CollectionChanged += Images_CollectionChanged; - e.NewValue.BackImages.CollectionChanged += Images_CollectionChanged; - e.NewValue.FoodLocations.CollectionChanged += Images_CollectionChanged; - } - } - private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + private void Images_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { StopCommand_ExecuteEvent(); } diff --git a/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/SelectGraphTypeWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/SelectGraphTypeWindowVM.cs new file mode 100644 index 0000000..5f60c9c --- /dev/null +++ b/VPet.ModMaker/ViewModels/ModEdit/AnimeEdit/SelectGraphTypeWindowVM.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HKW.HKWUtils.Extensions; +using VPet.ModMaker.Models; +using VPet.ModMaker.Models.ModModel; +using VPet_Simulator.Core; + +namespace VPet.ModMaker.ViewModels.ModEdit.AnimeEdit; + +public class SelectGraphTypeWindowVM : ObservableObjectX +{ + public SelectGraphTypeWindowVM() + { + PropertyChanged += SelectGraphTypeWindowVM_PropertyChanged; + } + + private void SelectGraphTypeWindowVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(CurrentPet)) + { + GraphTypes = new( + AnimeTypeModel.GraphTypes.Except(CurrentPet.Animes.Select(m => m.GraphType)) + ); + // 可添加多个项的类型 + GraphTypes.AddRange(AnimeTypeModel.HasNameAnimes); + } + else if (e.PropertyName == nameof(GraphType)) + { + if (GraphType.IsHasNameAnime()) + HasNameAnime = true; + else + HasNameAnime = false; + } + } + + #region CurrentPet + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private PetModel _currentPet = null!; + + /// + /// 当前宠物 + /// + public PetModel CurrentPet + { + get => _currentPet; + set => SetProperty(ref _currentPet, value); + } + #endregion + #region GraphType + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private GraphInfo.GraphType _graphType; + + /// + /// 动画类型 + /// + public GraphInfo.GraphType GraphType + { + get => _graphType; + set => SetProperty(ref _graphType, value); + } + #endregion + #region GraphTypes + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableSet _graphTypes = new(); + + /// + /// 动画类型列表 + /// + public ObservableSet GraphTypes + { + get => _graphTypes; + set => SetProperty(ref _graphTypes, value); + } + #endregion + #region AnimeName + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _animeName = string.Empty; + + /// + /// 动画名称 + /// + public string AnimeName + { + get => _animeName; + set => SetProperty(ref _animeName, value); + } + #endregion + + #region HasNameAnime + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool _hasNameAnime = true; + + /// + /// 具有动画名称 + /// + public bool HasNameAnime + { + get => _hasNameAnime; + set => SetProperty(ref _hasNameAnime, value); + } + #endregion +} diff --git a/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs index 4644a53..6b63dd4 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs @@ -35,16 +35,16 @@ public class I18nEditWindowVM : ObservableObjectX { } // /// // /// 全部I18n数据 // /// -// public ObservableCollection I18nDatas { get; } = new(); +// public ObservableList I18nDatas { get; } = new(); // /// // /// 显示的I18n数据 // /// // #region ShowI18nDatas // [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private ObservableCollection _showI18nDatas; +// private ObservableList _showI18nDatas; -// public ObservableCollection ShowI18nDatas +// public ObservableList ShowI18nDatas // { // get => _showI18nDatas; // set => SetProperty(ref _showI18nDatas, value); @@ -54,7 +54,7 @@ public class I18nEditWindowVM : ObservableObjectX { } // /// // /// 搜索目标列表 // /// -// public ObservableCollection SearchTargets { get; } = new() { nameof(ModInfoModel.Id) }; +// public ObservableList SearchTargets { get; } = new() { nameof(ModInfoModel.Id) }; // /// // /// 搜索目标 @@ -117,7 +117,7 @@ public class I18nEditWindowVM : ObservableObjectX { } // /// // /// // /// -// private void CultureNames_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) +// private void CultureNames_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) // { // if (e.Action is NotifyCollectionChangedAction.Add) // { diff --git a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs index 2ecf0e2..9916454 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs @@ -26,7 +26,8 @@ public class ModEditWindowVM : ObservableObjectX { public ModEditWindowVM(ModEditWindow window) { - I18nEditWindow.Initialize(); + //TODO + //I18nEditWindow.Initialize(); ModEditWindow = window; ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; AddCultureCommand.ExecuteCommand += AddCultureCommand_ExecuteCommand; @@ -210,8 +211,8 @@ public class ModEditWindowVM : ObservableObjectX is not MessageBoxResult.Yes ) return; - ModInfo.I18nDatas[culture].Name = ModInfo.Id; - ModInfo.I18nDatas[culture].Description = ModInfo.DescriptionId; + ModInfo.I18nDatas[culture].Name = ModInfo.ID; + ModInfo.I18nDatas[culture].Description = ModInfo.DescriptionID; foreach (var food in ModInfo.Foods) { food.I18nDatas[culture].Name = food.ID; @@ -229,10 +230,10 @@ public class ModEditWindowVM : ObservableObjectX foreach (var pet in ModInfo.Pets) { pet.I18nDatas[culture].Name = pet.ID; - pet.I18nDatas[culture].PetName = pet.PetNameId; - pet.I18nDatas[culture].Description = pet.DescriptionId; + pet.I18nDatas[culture].PetName = pet.PetNameID; + pet.I18nDatas[culture].Description = pet.DescriptionID; foreach (var work in pet.Works) - work.I18nDatas[culture].Name = work.Id; + work.I18nDatas[culture].Name = work.ID; } } #endregion @@ -311,7 +312,7 @@ public class ModEditWindowVM : ObservableObjectX ); return false; } - if (string.IsNullOrWhiteSpace(model.Id)) + if (string.IsNullOrWhiteSpace(model.ID)) { MessageBox.Show("Id不可为空".Translate(), "", MessageBoxButton.OK, MessageBoxImage.Warning); return false; diff --git a/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MoveEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MoveEditWindowVM.cs index b7879f0..8afc66a 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MoveEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MoveEditWindowVM.cs @@ -14,9 +14,16 @@ namespace VPet.ModMaker.ViewModels.ModEdit.MoveEdit; public class MoveEditWindowVM : ObservableObjectX { - #region Value - public PetModel CurrentPet { get; set; } - public MoveModel OldMove { get; set; } + public MoveEditWindowVM() + { + AddImageCommand.ExecuteCommand += AddImageCommand_ExecuteCommand; + ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; + //Image.ValueChanged += Image_ValueChanged; + } + + #region Property + public PetModel CurrentPet { get; set; } = null!; + public MoveModel? OldMove { get; set; } #region Move [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -51,9 +58,9 @@ public class MoveEditWindowVM : ObservableObjectX #endregion #region Image [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _image; + private BitmapImage? _image; - public BitmapImage Image + public BitmapImage? Image { get => _image; set => SetProperty(ref _image, value); @@ -63,13 +70,6 @@ public class MoveEditWindowVM : ObservableObjectX public ObservableCommand AddImageCommand { get; } = new(); public ObservableCommand ChangeImageCommand { get; } = new(); #endregion - public MoveEditWindowVM() - { - AddImageCommand.ExecuteCommand += AddImage; - ChangeImageCommand.ExecuteCommand += ChangeImage; - //TODO - //Image.ValueChanged += Image_ValueChanged; - } private void Image_ValueChanged( ObservableValue sender, @@ -84,28 +84,26 @@ public class MoveEditWindowVM : ObservableObjectX Image?.StreamSource?.Close(); } - private void AddImage() + private void AddImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); } } - private void ChangeImage() + private void ChangeImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { Image?.StreamSource?.Close(); diff --git a/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MovePageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MovePageVM.cs index 14f773a..e9be950 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MovePageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/MoveEdit/MovePageVM.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using HKW.HKWUtils.Extensions; using HKW.HKWUtils.Observable; using LinePutScript.Localization.WPF; using VPet.ModMaker.Models; @@ -15,27 +17,50 @@ namespace VPet.ModMaker.ViewModels.ModEdit.MoveEdit; public class MovePageVM : ObservableObjectX { + public MovePageVM() + { + Moves = new() + { + Filter = f => f.Graph.Contains(Search, StringComparison.OrdinalIgnoreCase), + FilteredList = new() + }; + PropertyChanged += MovePageVM_PropertyChanged; + + AddCommand.ExecuteCommand += AddCommand_ExecuteCommand; + EditCommand.ExecuteCommand += EditCommand_ExecuteCommand; + RemoveCommand.ExecuteCommand += RemoveCommand_ExecuteCommand; + } + public static ModInfoModel ModInfo => ModInfoModel.Current; - #region Value + #region Property #region ShowMoves [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableCollection _showMoves; + private ObservableFilterList> _moves; - public ObservableCollection ShowMoves + public ObservableFilterList> Moves { - get => _showMoves; - set => SetProperty(ref _showMoves, value); + get => _moves; + set => SetProperty(ref _moves, value); } #endregion - public ObservableCollection Moves => CurrentPet.Value.Moves; - public ObservableCollection Pets => ModInfoModel.Current.Pets; - public ObservableValue CurrentPet { get; } = new(new()); + public static ObservableList Pets => ModInfoModel.Current.Pets; + + #region CurrentPet + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private PetModel _currentPet; + + public PetModel CurrentPet + { + get => _currentPet; + set => SetProperty(ref _currentPet, value); + } + #endregion #region Search [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _search; + private string _search = string.Empty; public string Search { @@ -49,83 +74,49 @@ public class MovePageVM : ObservableObjectX public ObservableCommand EditCommand { get; } = new(); public ObservableCommand RemoveCommand { get; } = new(); #endregion - public MovePageVM() + private void MovePageVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) { - ShowMoves = Moves; - CurrentPet.ValueChanged += CurrentPet_ValueChanged; - //TODO - //Search.ValueChanged += Search_ValueChanged; - - AddCommand.ExecuteCommand += Add; - EditCommand.ExecuteCommand += Edit; - RemoveCommand.ExecuteCommand += Remove; - } - - private void CurrentPet_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - //ShowMoves.Value = e.NewValue.Moves; - } - - private void Search_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - if (string.IsNullOrWhiteSpace(e.NewValue)) + if (e.PropertyName == nameof(CurrentPet)) { - ShowMoves = Moves; + Moves.Clear(); + Moves.AddRange(CurrentPet.Moves); } - else + else if (e.PropertyName == nameof(Search)) { - ShowMoves = new( - Moves.Where(m => m.Graph.Contains(e.NewValue, StringComparison.OrdinalIgnoreCase)) - ); + Moves.Refresh(); } } public void Close() { } - private void Add() + private void AddCommand_ExecuteCommand() { var window = new MoveEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; + vm.CurrentPet = CurrentPet; window.ShowDialog(); if (window.IsCancel) return; Moves.Add(vm.Move); } - public void Edit(MoveModel model) + public void EditCommand_ExecuteCommand(MoveModel model) { var window = new MoveEditWindow(); var vm = window.ViewModel; - vm.CurrentPet = CurrentPet.Value; + vm.CurrentPet = CurrentPet; vm.OldMove = model; var newMove = vm.Move = new(model); window.ShowDialog(); if (window.IsCancel) return; Moves[Moves.IndexOf(model)] = newMove; - if (ShowMoves.Count != Moves.Count) - ShowMoves[ShowMoves.IndexOf(model)] = newMove; } - private void Remove(MoveModel model) + private void RemoveCommand_ExecuteCommand(MoveModel model) { if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No) return; - if (ShowMoves.Count == Moves.Count) - { - Moves.Remove(model); - } - else - { - ShowMoves.Remove(model); - Moves.Remove(model); - } + Moves.Remove(model); } } diff --git a/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetEditWindowVM.cs index 8266151..01e63ff 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetEditWindowVM.cs @@ -15,17 +15,25 @@ namespace VPet.ModMaker.ViewModels.ModEdit.PetEdit; public class PetEditWindowVM : ObservableObjectX { - public I18nHelper I18nData => I18nHelper.Current; - public PetModel OldPet { get; set; } + public PetEditWindowVM() + { + AddImageCommand.ExecuteCommand += AddImageCommand_ExecuteCommand; + ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; + //Image.ValueChanged += Image_ValueChanged; + } + + #region Property + public static I18nHelper I18nData => I18nHelper.Current; + public PetModel? OldPet { get; set; } #region Pet [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private PetModel _Pet; + private PetModel _pet = new(); public PetModel Pet { - get => _Pet; - set => SetProperty(ref _Pet, value); + get => _pet; + set => SetProperty(ref _pet, value); } #endregion @@ -41,7 +49,7 @@ public class PetEditWindowVM : ObservableObjectX #endregion #region LengthRatio [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private double _lengthRatio = 250 / 500; + private double _lengthRatio = 0.5; public double LengthRatio { @@ -51,26 +59,20 @@ public class PetEditWindowVM : ObservableObjectX #endregion #region Image [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private BitmapImage _image; + private BitmapImage? _image; - public BitmapImage Image + public BitmapImage? Image { get => _image; set => SetProperty(ref _image, value); } #endregion + #endregion + #region Command public ObservableCommand AddImageCommand { get; } = new(); public ObservableCommand ChangeImageCommand { get; } = new(); #endregion - public PetEditWindowVM() - { - AddImageCommand.ExecuteCommand += AddImage; - ChangeImageCommand.ExecuteCommand += ChangeImage; - //TODO - //Image.ValueChanged += Image_ValueChanged; - } - private void Image_ValueChanged( ObservableValue sender, ValueChangedEventArgs e @@ -84,28 +86,26 @@ public class PetEditWindowVM : ObservableObjectX Image?.CloseStream(); } - private void AddImage() + private void AddImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); } } - private void ChangeImage() + private void ChangeImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { Image?.StreamSource?.Close(); diff --git a/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetPageVM.cs index 1c6825d..abe73c8 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetPageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/PetEdit/PetPageVM.cs @@ -24,9 +24,9 @@ public class PetPageVM : ObservableObjectX FilteredList = new() }; - AddCommand.ExecuteCommand += Add; - EditCommand.ExecuteCommand += Edit; - RemoveCommand.ExecuteCommand += Remove; + AddCommand.ExecuteCommand += AddCommand_ExecuteCommand; + EditCommand.ExecuteCommand += EditCommand_ExecuteCommand; + RemoveCommand.ExecuteCommand += RemoveCommand_ExecuteCommand; } public static ModInfoModel ModInfo => ModInfoModel.Current; @@ -66,7 +66,7 @@ public class PetPageVM : ObservableObjectX public void Close() { } - private void Add() + private void AddCommand_ExecuteCommand() { var window = new PetEditWindow(); var vm = window.ViewModel; @@ -76,7 +76,7 @@ public class PetPageVM : ObservableObjectX Pets.Add(vm.Pet); } - public void Edit(PetModel model) + public void EditCommand_ExecuteCommand(PetModel model) { if (model.FromMain) { @@ -106,7 +106,7 @@ public class PetPageVM : ObservableObjectX model.Close(); } - private void Remove(PetModel model) + private void RemoveCommand_ExecuteCommand(PetModel model) { if (model.FromMain) { diff --git a/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs index 0bb0692..ff98460 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs @@ -29,7 +29,7 @@ public class SaveTranslationModWindowVM : ObservableObjectX CheckCultures { get; } = []; + public ObservableList CheckCultures { get; } = []; #endregion #region Command diff --git a/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkEditWindowVM.cs index 957dd51..b8a2036 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkEditWindowVM.cs @@ -1,29 +1,109 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; +using HKW.HKWUtils.Extensions; using HKW.HKWUtils.Observable; using LinePutScript.Localization.WPF; using Microsoft.Win32; using VPet.ModMaker.Models; +using VPet.ModMaker.Models.ModModel; using VPet_Simulator.Windows.Interface; namespace VPet.ModMaker.ViewModels.ModEdit.WorkEdit; public class WorkEditWindowVM : ObservableObjectX { + public WorkEditWindowVM() + { + PropertyChangedX += WorkEditWindowVM_PropertyChangedX; + Work.PropertyChanged += NewWork_PropertyChanged; + AddImageCommand.ExecuteCommand += AddImageCommand_ExecuteCommand; + ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; + FixOverLoadCommand.ExecuteCommand += FixOverLoadCommand_ExecuteCommand; + } + + private void WorkEditWindowVM_PropertyChangedX( + WorkEditWindowVM sender, + PropertyChangedXEventArgs e + ) + { + if (e.PropertyName == nameof(Work)) + { + var newWork = e.NewValue as WorkModel; + var oldWork = e.OldValue as WorkModel; + if (oldWork is not null) + { + oldWork.PropertyChanged -= NewWork_PropertyChanged; + } + if (newWork is not null) + { + newWork.PropertyChanged -= NewWork_PropertyChanged; + newWork.PropertyChanged += NewWork_PropertyChanged; + SetGraphImage(newWork); + } + } + } + + private void NewWork_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (sender is not WorkModel workModel) + return; + if (e.PropertyName == nameof(WorkModel.Graph)) + { + SetGraphImage(workModel); + } + } + + private void SetGraphImage(WorkModel workModel) + { + if (CurrentPet is null) + return; + var graph = workModel.Graph; + Image?.CloseStream(); + Image = null; + // 随机挑一张图片 + if ( + CurrentPet.Animes.FirstOrDefault( + a => + a.GraphType is VPet_Simulator.Core.GraphInfo.GraphType.Work + && a.Name.Equals(graph, StringComparison.OrdinalIgnoreCase), + null! + ) + is not AnimeTypeModel anime + ) + return; + if (anime.HappyAnimes.HasValue()) + { + Image = anime.HappyAnimes.Random().Images.Random().Image.CloneStream(); + } + else if (anime.NomalAnimes.HasValue()) + { + Image = anime.NomalAnimes.Random().Images.Random().Image.CloneStream(); + } + else if (anime.PoorConditionAnimes.HasValue()) + { + Image = anime.PoorConditionAnimes.Random().Images.Random().Image.CloneStream(); + } + else if (anime.IllAnimes.HasValue()) + { + Image = anime.IllAnimes.Random().Images.Random().Image.CloneStream(); + } + } + public static ModInfoModel ModInfo => ModInfoModel.Current; public static I18nHelper I18nData => I18nHelper.Current; - #region Value - public PetModel CurrentPet { get; set; } - public WorkModel OldWork { get; set; } + #region Property + public PetModel CurrentPet { get; set; } = null!; + public WorkModel? OldWork { get; set; } #region Work [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private WorkModel _work; + private WorkModel _work = new(); public WorkModel Work { @@ -52,52 +132,59 @@ public class WorkEditWindowVM : ObservableObjectX set => SetProperty(ref _lengthRatio, value); } #endregion + #region Image + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private BitmapImage? _image; + + /// + /// 图片 + /// + public BitmapImage? Image + { + get => _image; + set => SetProperty(ref _image, value); + } + #endregion #region Command public ObservableCommand AddImageCommand { get; } = new(); public ObservableCommand ChangeImageCommand { get; } = new(); public ObservableCommand FixOverLoadCommand { get; } = new(); #endregion - public WorkEditWindowVM() - { - AddImageCommand.ExecuteCommand += AddImage; - ChangeImageCommand.ExecuteCommand += ChangeImage; - FixOverLoadCommand.ExecuteCommand += FixOverLoadCommand_ExecuteCommand; - } - private void FixOverLoadCommand_ExecuteCommand() { - //var work = Work.ToWork(); - //work.FixOverLoad(); - //Work = new(work); + Work.FixOverLoad(); } - private void AddImage() + private void AddImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { - Work.Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); + Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); } } - private void ChangeImage() + private void ChangeImageCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "选择图片".Translate(), - Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() - }; + var openFileDialog = new OpenFileDialog() + { + Title = "选择图片".Translate(), + Filter = $"图片|*.jpg;*.jpeg;*.png;*.bmp".Translate() + }; if (openFileDialog.ShowDialog() is true) { - Work.Image?.CloseStream(); - Work.Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); + Image?.CloseStream(); + Image = NativeUtils.LoadImageToMemoryStream(openFileDialog.FileName); } } + + public void Close() + { + Image?.CloseStream(); + } } diff --git a/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkPageVM.cs b/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkPageVM.cs index c91e13b..39343a7 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkPageVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/WorkEdit/WorkPageVM.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; +using HKW.HKWUtils.Extensions; using HKW.HKWUtils.Observable; using LinePutScript.Localization.WPF; using VPet.ModMaker.Models; @@ -15,22 +17,34 @@ namespace VPet.ModMaker.ViewModels.ModEdit.WorkEdit; public class WorkPageVM : ObservableObjectX { + public WorkPageVM() + { + Works = new() + { + Filter = f => f.ID.Contains(Search, StringComparison.OrdinalIgnoreCase), + FilteredList = new() + }; + PropertyChanged += WorkPageVM_PropertyChanged; + AddCommand.ExecuteCommand += AddCommand_ExecuteCommand; + EditCommand.ExecuteCommand += EditCommand_ExecuteCommand; + RemoveCommand.ExecuteCommand += RemoveCommand_ExecuteCommand; + } + public static ModInfoModel ModInfo => ModInfoModel.Current; - #region Value - #region ShowWorks + #region Property + #region Works [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableCollection _showWorks; + private ObservableFilterList> _works; - public ObservableCollection ShowWorks + public ObservableFilterList> Works { - get => _showWorks; - set => SetProperty(ref _showWorks, value); + get => _works; + set => SetProperty(ref _works, value); } #endregion - public ObservableCollection Works => CurrentPet.Works; - public ObservableCollection Pets => ModInfoModel.Current.Pets; + public static ObservableList Pets => ModInfoModel.Current.Pets; #region CurrentPet [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -45,7 +59,7 @@ public class WorkPageVM : ObservableObjectX #region Search [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _search; + private string _search = string.Empty; public string Search { @@ -59,44 +73,20 @@ public class WorkPageVM : ObservableObjectX public ObservableCommand EditCommand { get; } = new(); public ObservableCommand RemoveCommand { get; } = new(); #endregion - public WorkPageVM() + private void WorkPageVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) { - ShowWorks = Works; - //TODO - //CurrentPet.ValueChanged += CurrentPet_ValueChanged; - //Search.ValueChanged += Search_ValueChanged; - - AddCommand.ExecuteCommand += Add; - EditCommand.ExecuteCommand += Edit; - RemoveCommand.ExecuteCommand += Remove; - } - - private void CurrentPet_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - ShowWorks = e.NewValue.Works; - } - - private void Search_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - if (string.IsNullOrWhiteSpace(e.NewValue)) + if (e.PropertyName == nameof(CurrentPet)) { - ShowWorks = Works; + Works.Clear(); + Works.AddRange(CurrentPet.Works); } - else + else if (e.PropertyName == nameof(Search)) { - ShowWorks = new( - Works.Where(m => m.Id.Contains(e.NewValue, StringComparison.OrdinalIgnoreCase)) - ); + Works.Refresh(); } } - private void Add() + private void AddCommand_ExecuteCommand() { var window = new WorkEditWindow(); var vm = window.ViewModel; @@ -107,7 +97,7 @@ public class WorkPageVM : ObservableObjectX Works.Add(vm.Work); } - public void Edit(WorkModel model) + public void EditCommand_ExecuteCommand(WorkModel model) { var window = new WorkEditWindow(); var vm = window.ViewModel; @@ -118,22 +108,14 @@ public class WorkPageVM : ObservableObjectX if (window.IsCancel) return; Works[Works.IndexOf(model)] = newWork; - if (ShowWorks.Count != Works.Count) - ShowWorks[ShowWorks.IndexOf(model)] = newWork; + model.Close(); } - private void Remove(WorkModel model) + private void RemoveCommand_ExecuteCommand(WorkModel model) { if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No) return; - if (ShowWorks.Count == Works.Count) - { - Works.Remove(model); - } - else - { - ShowWorks.Remove(model); - Works.Remove(model); - } + Works.Remove(model); + model.Close(); } } diff --git a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs index 0b8da68..836f25c 100644 --- a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -8,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; +using HKW.HKWUtils.Extensions; using HKW.HKWUtils.Observable; using LinePutScript; using LinePutScript.Converter; @@ -23,43 +25,63 @@ namespace VPet.ModMaker.ViewModels; public class ModMakerWindowVM : ObservableObjectX { - #region Value - public ModMakerWindow ModMakerWindow { get; } + public ModMakerWindowVM(ModMakerWindow window) + { + Histories = new() + { + Filter = f => f.ID.Contains(Search, StringComparison.OrdinalIgnoreCase), + FilteredList = new() + }; + LoadHistories(); + ModMakerWindow = window; + PropertyChanged += ModMakerWindowVM_PropertyChanged; + CreateNewModCommand.ExecuteCommand += CreateNewModCommand_ExecuteCommand; + LoadModFromFileCommand.ExecuteCommand += LoadModFromFileCommand_ExecuteCommand; + ClearHistoriesCommand.ExecuteCommand += ClearHistoriesCommand_ExecuteCommand; + RemoveHistoryCommand.ExecuteCommand += RemoveHistoryCommand_ExecuteCommand; + } - public ModEditWindow ModEditWindow { get; private set; } + private void ModMakerWindowVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Search)) + { + Histories.Refresh(); + } + } + + #region Property + public ModMakerWindow ModMakerWindow { get; } = null!; + + public ModEditWindow ModEditWindow { get; private set; } = null!; /// /// 历史搜索文本 /// #region HistoriesSearchText [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _historiesSearchText; + private string _search = string.Empty; - public string HistoriesSearchText + public string Search { - get => _historiesSearchText; - set => SetProperty(ref _historiesSearchText, value); - } - #endregion - - /// - /// 显示的历史 - /// - #region ShowHistories - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ObservableCollection _showHistories; - - public ObservableCollection ShowHistories - { - get => _showHistories; - set => SetProperty(ref _showHistories, value); + get => _search; + set => SetProperty(ref _search, value); } #endregion /// /// 历史 /// - public ObservableCollection Histories { get; set; } = new(); + #region Histories + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ObservableFilterList> _histories = null!; + + public ObservableFilterList> Histories + { + get => _histories; + set => SetProperty(ref _histories, value); + } + #endregion + #endregion #region Command /// @@ -83,32 +105,8 @@ public class ModMakerWindowVM : ObservableObjectX public ObservableCommand RemoveHistoryCommand { get; } = new(); #endregion - public ModMakerWindowVM(ModMakerWindow window) - { - LoadHistories(); - ModMakerWindow = window; - //TODO - ShowHistories = Histories; - CreateNewModCommand.ExecuteCommand += CreateNewMod; - LoadModFromFileCommand.ExecuteCommand += LoadModFromFile; - ClearHistoriesCommand.ExecuteCommand += ClearHistories; - RemoveHistoryCommand.ExecuteCommand += RemoveHistory; - //HistoriesSearchText.ValueChanged += HistoriesSearchText_ValueChanged; - } - - private void HistoriesSearchText_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e - ) - { - if (string.IsNullOrEmpty(e.NewValue)) - ShowHistories = Histories; - else - ShowHistories = new(Histories.Where(i => i.Id.Contains(e.NewValue))); - } - #region History - private void RemoveHistory(ModMakeHistory value) + private void RemoveHistoryCommand_ExecuteCommand(ModMakeHistory value) { Histories.Remove(value); SaveHistories(); @@ -122,14 +120,14 @@ public class ModMakerWindowVM : ObservableObjectX if (File.Exists(ModMakerInfo.HistoryFile) is false) return; var lps = new LPS(File.ReadAllText(ModMakerInfo.HistoryFile)); + var set = new HashSet(); foreach (var line in lps) { if (LPSConvert.DeserializeObject(line) is not ModMakeHistory history) continue; - if (Histories.All(h => h.InfoFile != history.InfoFile)) - Histories.Add(history); + set.Add(history); } - Histories = new(Histories.OrderByDescending(h => h.LastTime)); + Histories.AddRange(set.OrderByDescending(h => h.LastTime)); } /// @@ -158,7 +156,7 @@ public class ModMakerWindowVM : ObservableObjectX is ModMakeHistory history ) { - history.Id = modInfo.Id; + history.ID = modInfo.ID; history.SourcePath = modInfo.SourcePath; history.LastTime = DateTime.Now; } @@ -167,7 +165,7 @@ public class ModMakerWindowVM : ObservableObjectX Histories.Add( new() { - Id = modInfo.Id, + ID = modInfo.ID, SourcePath = modInfo.SourcePath, LastTime = DateTime.Now, } @@ -175,14 +173,14 @@ public class ModMakerWindowVM : ObservableObjectX } } - private void ClearHistories() + private void ClearHistoriesCommand_ExecuteCommand() { if ( MessageBox.Show("确定要清空吗?".Translate(), "", MessageBoxButton.YesNo) is not MessageBoxResult.Yes ) return; - ShowHistories.Clear(); + Histories.Clear(); Histories.Clear(); File.WriteAllText(ModMakerInfo.HistoryFile, string.Empty); } @@ -192,7 +190,7 @@ public class ModMakerWindowVM : ObservableObjectX /// /// 创建新模组 /// - public void CreateNewMod() + public void CreateNewModCommand_ExecuteCommand() { ModInfoModel.Current = new(); ShowEditWindow(); @@ -241,18 +239,17 @@ public class ModMakerWindowVM : ObservableObjectX /// /// 从文件载入模组 /// - public void LoadModFromFile() + public void LoadModFromFileCommand_ExecuteCommand() { - OpenFileDialog openFileDialog = - new() - { - Title = "模组信息文件".Translate(), - Filter = $"LPS文件|*.lps;".Translate(), - FileName = "info.lps" - }; + var openFileDialog = new OpenFileDialog() + { + Title = "模组信息文件".Translate(), + Filter = $"LPS文件|*.lps;".Translate(), + FileName = "info.lps" + }; if (openFileDialog.ShowDialog() is true) { - LoadMod(Path.GetDirectoryName(openFileDialog.FileName)); + LoadMod(Path.GetDirectoryName(openFileDialog.FileName)!); } } @@ -279,19 +276,40 @@ public class ModMakerWindowVM : ObservableObjectX { var modInfo = new ModInfoModel(loader); EditMod(modInfo); + // 更新模组 + if (ModUpdataHelper.CanUpdata(modInfo)) + { + pendingHandler.Hide(); + if ( + MessageBox.Show( + ModEditWindow.Current, + "是否更新模组\n当前版本: {0}\n最新版本: {1}".Translate( + modInfo.ModVersion, + ModUpdataHelper.LastVersion + ), + "更新模组".Translate(), + MessageBoxButton.YesNo + ) is MessageBoxResult.Yes + ) + { + if (ModUpdataHelper.Updata(modInfo)) + MessageBox.Show("更新完成, 请手动保存".Translate()); + } + } pendingHandler.Close(); } catch (Exception ex) { pendingHandler.Close(); ModEditWindow?.Close(); - ModEditWindow = null; + ModEditWindow = null!; ModInfoModel.Current?.Close(); I18nHelper.Current = new(); I18nEditWindow.Current?.Close(true); ModMakerWindow.Show(); ModMakerWindow.Activate(); MessageBox.Show(ModMakerWindow, "模组载入失败:\n{0}".Translate(ex)); + GC.Collect(); } } #endregion diff --git a/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs b/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs index a547267..e6dec70 100644 --- a/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs +++ b/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs @@ -39,12 +39,12 @@ public partial class AddCultureWindow : WindowX TextBox_Lang.Dispatcher.InvokeAsync(TextBox_Lang.SelectAll); } - private void Button_Cancel_Click(object sender, RoutedEventArgs e) + private void Button_Cancel_Click(object? sender, RoutedEventArgs e) { Close(); } - private void Button_Yes_Click(object sender, RoutedEventArgs e) + private void Button_Yes_Click(object? sender, RoutedEventArgs e) { if (string.IsNullOrWhiteSpace(ViewModel.Culture)) { @@ -60,7 +60,7 @@ public partial class AddCultureWindow : WindowX Close(); } - private void Hyperlink_Click(object sender, RoutedEventArgs e) + private void Hyperlink_Click(object? sender, RoutedEventArgs e) { Process.Start( new ProcessStartInfo( diff --git a/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml b/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml index f13235e..a474b2c 100644 --- a/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml +++ b/VPet.ModMaker/Views/ModEdit/AnimeEdit/AnimeEditWindow.xaml @@ -68,9 +68,9 @@ - + pu:TextBoxHelper.Watermark="{ll:Str 动画ID(非必要)}" + Text="{Binding ID, UpdateSourceTrigger=PropertyChanged}" /> + - + -