diff --git a/VPet.ModMaker/Models/ModLoader.cs b/VPet.ModMaker/Models/ModLoader.cs index 380f05b..6116e7c 100644 --- a/VPet.ModMaker/Models/ModLoader.cs +++ b/VPet.ModMaker/Models/ModLoader.cs @@ -238,7 +238,7 @@ public class ModLoader return; foreach (var dis in langDirectory.EnumerateDirectories()) { - I18nDatas.TryAdd(dis.Name, new()); + I18nDatas.TryAdd(dis.Name, []); foreach (FileInfo fi in dis.EnumerateFiles("*.lps")) { var lps = new LPS(File.ReadAllText(fi.FullName)); diff --git a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs index fef2d0f..5535b02 100644 --- a/VPet.ModMaker/Models/ModModel/ClickTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/ClickTextModel.cs @@ -127,7 +127,7 @@ public class ClickTextModel : ObservableObjectX [AdaptIgnore] public string Text { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } #endregion diff --git a/VPet.ModMaker/Models/ModModel/FoodModel.cs b/VPet.ModMaker/Models/ModModel/FoodModel.cs index e5c32aa..992355a 100644 --- a/VPet.ModMaker/Models/ModModel/FoodModel.cs +++ b/VPet.ModMaker/Models/ModModel/FoodModel.cs @@ -119,7 +119,7 @@ public class FoodModel : ObservableObjectX [AdaptIgnore] public string Name { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } diff --git a/VPet.ModMaker/Models/ModModel/LowTextModel.cs b/VPet.ModMaker/Models/ModModel/LowTextModel.cs index 0001f93..da05fa7 100644 --- a/VPet.ModMaker/Models/ModModel/LowTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/LowTextModel.cs @@ -74,7 +74,7 @@ public class LowTextModel : ObservableObjectX [AdaptIgnore] public string Text { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } #endregion diff --git a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs index 0e52755..3654025 100644 --- a/VPet.ModMaker/Models/ModModel/ModInfoModel.cs +++ b/VPet.ModMaker/Models/ModModel/ModInfoModel.cs @@ -123,6 +123,7 @@ public class ModInfoModel : ObservableObjectX RefreshAllID(); if (I18nResource.CultureDatas.HasValue()) RefreshID(); + I18nResource.FillDefaultValue(); } private void ModInfoModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) @@ -142,17 +143,18 @@ public class ModInfoModel : ObservableObjectX /// public static ModInfoModel Current { get; set; } = new(); - public I18nResource I18nResource { get; } = new(); + public I18nResource I18nResource { get; } = + new() { FillDefaultValueForNewCulture = true, DefaultValue = string.Empty }; #region I18nData public string Name { - get => I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => I18nResource.GetCurrentCultureDataOrDefault(ID); set => I18nResource.SetCurrentCultureData(ID, value); } public string Description { - get => I18nResource.GetCurrentCultureDataOrDefault(DescriptionID, string.Empty); + get => I18nResource.GetCurrentCultureDataOrDefault(DescriptionID); set => I18nResource.SetCurrentCultureData(DescriptionID, value); } #endregion @@ -448,15 +450,16 @@ public class ModInfoModel : ObservableObjectX { if (modLoader.I18nDatas.HasValue() is false) return; + foreach (var cultureDatas in modLoader.I18nDatas) { var culture = CultureInfo.GetCultureInfo(cultureDatas.Key); I18nResource.AddCulture(culture); foreach (var data in cultureDatas.Value) - I18nResource.AddCultureData(culture, data.Key, data.Value); + I18nResource.SetCultureData(culture, data.Key, data.Value); } if (I18nResource.SetCurrentCulture(CultureInfo.CurrentCulture) is false) - I18nResource.SetCurrentCulture(I18nResource.CultureDatas.First().Key); + I18nResource.SetCurrentCulture(I18nResource.Cultures.First()); I18nResource.I18nObjectInfos.Add( new( this, @@ -613,22 +616,15 @@ public class ModInfoModel : ObservableObjectX new Line("itemid", ItemID.ToString()), new Line("cachedate", DateTime.Now.Date.ToString("s")) }; - foreach (var cultureData in Current.I18nResource.CultureDatas) + foreach (var culture in Current.I18nResource.Cultures) { lps.Add( - new Line("cultureDatas", cultureData.Key.Name) + new Line("cultureDatas", culture.Name) { - new Sub( - ID, - I18nResource.GetCultureDataOrDefault(cultureData.Key.Name, ID, string.Empty) - ), + new Sub(ID, I18nResource.GetCultureDataOrDefault(culture, ID, string.Empty)), new Sub( DescriptionID, - I18nResource.GetCultureDataOrDefault( - cultureData.Key.Name, - DescriptionID, - string.Empty - ) + I18nResource.GetCultureDataOrDefault(culture, DescriptionID, string.Empty) ), } ); @@ -756,15 +752,18 @@ public class ModInfoModel : ObservableObjectX { var langPath = Path.Combine(path, "lang"); Directory.CreateDirectory(langPath); - foreach (var cultureData in I18nResource.CultureDatas) + foreach (var culture in I18nResource.Cultures) { - var culturePath = Path.Combine(langPath, cultureData.Key.Name); + var culturePath = Path.Combine(langPath, culture.Name); Directory.CreateDirectory(culturePath); - var cultureFile = Path.Combine(culturePath, $"{cultureData.Key.Name}.lps"); + var cultureFile = Path.Combine(culturePath, $"{culture.Name}.lps"); File.Create(cultureFile).Close(); var lps = new LPS(); - foreach (var data in cultureData.Value) - lps.Add(new Line(data.Key, data.Value)); + foreach (var datas in I18nResource.CultureDatas) + { + if (I18nResource.TryGetCultureData(culture, datas.Key, out var data)) + lps.Add(new Line(datas.Key, data)); + } File.WriteAllText(cultureFile, lps.ToString()); } } @@ -803,53 +802,23 @@ public class ModInfoModel : ObservableObjectX Current = null!; } - public void SaveTranslationMod(string path, IEnumerable cultures) + public void SaveTranslationMod(string path, IEnumerable cultures) { // 保存模型信息 SaveModInfo(path); // 保存文化数据 - var langPath = Path.Combine(path, "cultureDatas"); + var langPath = Path.Combine(path, "lang"); Directory.CreateDirectory(langPath); - foreach (var cultureName in cultures) + foreach (var culture in cultures) { - var culturePath = Path.Combine(langPath, cultureName); + var culturePath = Path.Combine(langPath, culture.Name); Directory.CreateDirectory(culturePath); - var cultureFile = Path.Combine(culturePath, $"{cultureName}.lps"); + var cultureFile = Path.Combine(culturePath, $"{culture}.lps"); File.Create(cultureFile).Close(); var lps = new LPS(); - //TODO - //foreach (var data in I18nEditWindow.Current.ViewModel.AllI18nDatas) - // lps.Add( - // new Line( - // data.Key, - // data.Value.Datas[I18nHelper.Current.CultureNames.IndexOf(cultureName)].Value - // ) - // ); + foreach (var data in I18nResource.CultureDatas.Values) + lps.Add(new Line(data.Key, data[culture])); File.WriteAllText(cultureFile, lps.ToString()); } } } - -//public class I18nModInfoModel : ObservableObjectX -//{ -// #region Name -// [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private string _name = string.Empty; - -// public string Name -// { -// get => _name; -// set => SetProperty(ref _name, value); -// } -// #endregion -// #region Description -// [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private string _description = string.Empty; - -// public string Description -// { -// get => _description; -// set => SetProperty(ref _description, value); -// } -// #endregion -//} diff --git a/VPet.ModMaker/Models/ModModel/PetModel.cs b/VPet.ModMaker/Models/ModModel/PetModel.cs index 782a8a3..882537c 100644 --- a/VPet.ModMaker/Models/ModModel/PetModel.cs +++ b/VPet.ModMaker/Models/ModModel/PetModel.cs @@ -196,7 +196,7 @@ public class PetModel : ObservableObjectX [AdaptIgnore] public string Name { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } diff --git a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs index c81fade..f276d3d 100644 --- a/VPet.ModMaker/Models/ModModel/SelectTextModel.cs +++ b/VPet.ModMaker/Models/ModModel/SelectTextModel.cs @@ -138,7 +138,7 @@ public class SelectTextModel : ObservableObjectX [AdaptIgnore] public string Text { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } diff --git a/VPet.ModMaker/Models/ModModel/WorkModel.cs b/VPet.ModMaker/Models/ModModel/WorkModel.cs index 0dd9478..d7defe7 100644 --- a/VPet.ModMaker/Models/ModModel/WorkModel.cs +++ b/VPet.ModMaker/Models/ModModel/WorkModel.cs @@ -129,7 +129,7 @@ public class WorkModel : ObservableObjectX [AdaptIgnore] public string Name { - get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID, string.Empty); + get => ModInfoModel.Current.I18nResource.GetCurrentCultureDataOrDefault(ID); set => ModInfoModel.Current.I18nResource.SetCurrentCultureData(ID, value); } #endregion diff --git a/VPet.ModMaker/Templates.xaml b/VPet.ModMaker/Templates.xaml index bc00863..a3dee4f 100644 --- a/VPet.ModMaker/Templates.xaml +++ b/VPet.ModMaker/Templates.xaml @@ -46,7 +46,7 @@ diff --git a/VPet.ModMaker/Utils/NativeExtensions.cs b/VPet.ModMaker/Utils/NativeExtensions.cs index 26f0ce1..6f623e0 100644 --- a/VPet.ModMaker/Utils/NativeExtensions.cs +++ b/VPet.ModMaker/Utils/NativeExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; @@ -118,27 +119,6 @@ public static class NativeExtensions stream.Seek(position, SeekOrigin.Begin); } - /// - /// 尝试添加 - /// - /// 键类型 - /// - /// - /// 键 - /// 值 - /// 成功为 失败为 - public static bool TryAdd( - this IDictionary dictionary, - TKey key, - TValue value - ) - { - if (dictionary.ContainsKey(key)) - return false; - dictionary.Add(key, value); - return true; - } - /// /// 流内容对比 /// @@ -290,4 +270,65 @@ public static class NativeExtensions catch { } }; } + + private static Dictionary _windowCloseStates = new(); + + /// + /// 设置关闭状态 + /// + /// + /// 关闭状态 + public static void SetCloseState(this Window window, WindowCloseState state) + { + window.Closing -= WindowCloseState_Closing; + window.Closing += WindowCloseState_Closing; + _windowCloseStates[window] = state; + } + + /// + /// 强制关闭 + /// + /// + public static void CloseX(this Window? window) + { + if (window is null) + return; + _windowCloseStates.Remove(window); + window.Closing -= WindowCloseState_Closing; + window.Close(); + } + + /// + /// 显示或者聚焦 + /// + /// + public static void ShowOrActivate(this Window? window) + { + if (window is null) + return; + if (window.IsVisible is false) + window.Show(); + window.Activate(); + } + + private static void WindowCloseState_Closing(object sender, CancelEventArgs e) + { + if (sender is not Window window) + return; + if (_windowCloseStates.TryGetValue(window, out var state) is false) + return; + if (state is WindowCloseState.Close) + return; + e.Cancel = true; + window.Visibility = + state is WindowCloseState.Hidden ? Visibility.Hidden : Visibility.Collapsed; + return; + } +} + +public enum WindowCloseState +{ + Close, + Hidden, + Collapsed } diff --git a/VPet.ModMaker/VPet.ModMaker.csproj b/VPet.ModMaker/VPet.ModMaker.csproj index 4a57a3a..4908813 100644 --- a/VPet.ModMaker/VPet.ModMaker.csproj +++ b/VPet.ModMaker/VPet.ModMaker.csproj @@ -28,8 +28,8 @@ - - + + \ No newline at end of file diff --git a/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs deleted file mode 100644 index 1994499..0000000 --- a/VPet.ModMaker/ViewModels/ModEdit/I18nEdit/I18nEditWindowVM.cs +++ /dev/null @@ -1,520 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HKW.HKWUtils.Observable; -using Mapster; -using VPet.ModMaker.Models; - -namespace VPet.ModMaker.ViewModels.ModEdit.I18nEdit; - -public class I18nEditWindowVM : ObservableObjectX { } -//{ -// public I18nEditWindowVM() -// { -// I18nDatas = new() -// { -// Filter = (d) => -// { -// if (SearchTarget == nameof(ModInfoModel.ID)) -// { -// return d.ID.Contains(Search, StringComparison.OrdinalIgnoreCase); -// } -// else -// { -// var cultureIndex = I18nHelper.Current.CultureNames.IndexOf(SearchTarget); -// throw new(); -// //return d.Datas[cultureIndex]() -// // .Contains(Search, StringComparison.OrdinalIgnoreCase); -// } -// }, -// FilteredList = new() -// }; -// SearchTarget = nameof(ModInfoModel.ID); -// PropertyChanged += I18nEditWindowVM_PropertyChanged; -// } - -// private void I18nEditWindowVM_PropertyChanged( -// object? sender, -// System.ComponentModel.PropertyChangedEventArgs e -// ) -// { -// if (e.PropertyName == nameof(Search)) -// { -// I18nDatas.Refresh(); -// } -// else if (e.PropertyName == nameof(SearchTarget)) -// { -// I18nDatas.Refresh(); -// } -// } - -// #region Search -// [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private string _search = string.Empty; - -// /// -// /// 搜索 -// /// -// public string Search -// { -// get => _search; -// set => SetProperty(ref _search, value); -// } -// #endregion - -// /// -// /// 全部I18n资源 (ID, I18nData) -// /// -// public Dictionary AllI18nDatas { get; } = new(); - -// /// -// /// 全部的I18n资源 -// /// -// #region ShowI18nDatas -// [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private ObservableFilterList> _i18nDatas; - -// public ObservableFilterList> I18nDatas -// { -// get => _i18nDatas; -// set => SetProperty(ref _i18nDatas, value); -// } -// #endregion - -// /// -// /// 搜索目标列表 -// /// -// public ObservableList SearchTargets { get; } = new() { nameof(ModInfoModel.ID) }; - -// /// -// /// 搜索目标 -// /// -// #region SearchTarget -// [DebuggerBrowsable(DebuggerBrowsableState.Never)] -// private string _searchTarget; - -// public string SearchTarget -// { -// get => _searchTarget; -// set => SetProperty(ref _searchTarget, value); -// } -// #endregion - -// /// -// /// 文化列表改变事件 -// /// -// /// -// /// -// private void CultureNames_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newCulture = (string)e.NewItems[0]; -// AddCulture(newCulture); -// SearchTargets.Add(newCulture); -// foreach (var data in AllI18nDatas) -// data.Value.Datas.Add(new()); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldCulture = (string)e.OldItems[0]; -// RemoveCulture(oldCulture); -// SearchTargets.Remove(oldCulture); -// foreach (var data in AllI18nDatas) -// { -// var value = data.Value.Datas[e.OldStartingIndex]; -// value.Group?.Remove(value); -// data.Value.Datas.RemoveAt(e.OldStartingIndex); -// } -// if (SearchTarget is null) -// SearchTarget = nameof(ModInfoModel.ID); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var oldCulture = (string)e.OldItems[0]; -// var newCulture = (string)e.NewItems[0]; -// ReplaceCulture(oldCulture, newCulture); -// SearchTargets[SearchTargets.IndexOf(oldCulture)] = newCulture; -// } -// } - -// #region LoadData -// /// -// /// 初始化I18n资源 -// /// -// /// -// public void InitializeI18nData(ModInfoModel model) -// { -// foreach (var culture in I18nHelper.Current.CultureNames) -// { -// AddCulture(culture); -// SearchTargets.Add(culture); -// } -// try -// { -// LoadFood(model); -// LoadClickText(model); -// LoadLowText(model); -// LoadSelectText(model); -// LoadPets(model); -// } -// catch -// { -// Close(); -// throw; -// } -// I18nHelper.Current.CultureNames.CollectionChanged -= CultureNames_CollectionChanged; -// I18nHelper.Current.CultureNames.CollectionChanged += CultureNames_CollectionChanged; -// } - -// /// -// /// 载入食物 -// /// -// /// -// private void LoadFood(ModInfoModel model) -// { -// foreach (var food in model.Foods) -// { -// AddData(food.ID, food, (m) => m.Name); -// AddData(food.DescriptionID, food, (m) => m.Description); -// } -// model.Foods.CollectionChanged += (s, e) => -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newModel = (FoodModel)e.NewItems[0]; -// AddData(newModel.ID, newModel, (m) => m.Name); -// AddData(newModel.DescriptionID, newModel, (m) => m.Description); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldModel = (FoodModel)e.OldItems[0]; -// RemoveData(oldModel.ID, oldModel, (m) => m.Name); -// RemoveData(oldModel.DescriptionID, oldModel, (m) => m.Description); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var newModel = (FoodModel)e.NewItems[0]; -// var oldModel = (FoodModel)e.OldItems[0]; -// ReplaceData(newModel.ID, newModel, (m) => m.Name); -// ReplaceData(newModel.DescriptionID, newModel, (m) => m.Description); -// } -// }; -// } - -// /// -// /// 载入点击文本 -// /// -// /// -// private void LoadClickText(ModInfoModel model) -// { -// foreach (var text in model.ClickTexts) -// { -// AddData(text.ID, text, (m) => m.Text); -// } -// model.ClickTexts.CollectionChanged += (s, e) => -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newModel = (ClickTextModel)e.NewItems[0]; -// AddData(newModel.ID, newModel, (m) => m.Text); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldModel = (ClickTextModel)e.OldItems[0]; -// RemoveData(oldModel.ID, oldModel, (m) => m.Text); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var newModel = (ClickTextModel)e.NewItems[0]; -// var oldModel = (ClickTextModel)e.OldItems[0]; -// ReplaceData(newModel.ID, newModel, (m) => m.Text); -// } -// }; -// } - -// /// -// /// 载入低状态为文本 -// /// -// /// -// private void LoadLowText(ModInfoModel model) -// { -// foreach (var text in model.LowTexts) -// { -// AddData(text.ID, text, (m) => m.Text); -// } -// model.LowTexts.CollectionChanged += (s, e) => -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newModel = (LowTextModel)e.NewItems[0]; -// AddData(newModel.ID, newModel, (m) => m.Text); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldModel = (LowTextModel)e.OldItems[0]; -// RemoveData(oldModel.ID, oldModel, (m) => m.Text); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var newModel = (LowTextModel)e.NewItems[0]; -// var oldModel = (LowTextModel)e.OldItems[0]; -// ReplaceData(newModel.ID, newModel, (m) => m.Text); -// } -// }; -// } - -// /// -// /// 载入选择文本 -// /// -// /// -// private void LoadSelectText(ModInfoModel model) -// { -// foreach (var text in model.SelectTexts) -// { -// AddData(text.ID, text, (m) => m.Text); -// AddData(text.ChooseId, text, (m) => m.Choose); -// } -// model.SelectTexts.CollectionChanged += (s, e) => -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newModel = (SelectTextModel)e.NewItems[0]; -// AddData(newModel.ID, newModel, (m) => m.Text); -// AddData(newModel.ChooseId, newModel, (m) => m.Choose); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldModel = (SelectTextModel)e.OldItems[0]; -// RemoveData(oldModel.ID, oldModel, (m) => m.Text); -// RemoveData(oldModel.ChooseId, oldModel, (m) => m.Choose); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var newModel = (SelectTextModel)e.NewItems[0]; -// var oldModel = (SelectTextModel)e.OldItems[0]; -// ReplaceData(newModel.ID, newModel, (m) => m.Text); -// ReplaceData(newModel.ChooseId, newModel, (m) => m.Choose); -// } -// }; -// } - -// /// -// /// 载入宠物 -// /// -// /// -// public void LoadPets(ModInfoModel model) -// { -// foreach (var pet in model.Pets) -// { -// if (pet.FromMain.Value) -// continue; -// AddData(pet.ID, pet, (m) => m.Name); -// AddData(pet.PetNameId, pet, (m) => m.PetName); -// AddData(pet.DescriptionID, pet, (m) => m.Description); -// foreach (var work in pet.Works) -// AddData(work.ID, work, (m) => m.Name); -// } -// model.Pets.CollectionChanged += (s, e) => -// { -// if (e.Action is NotifyCollectionChangedAction.Add) -// { -// var newModel = (PetModel)e.NewItems[0]; -// AddData(newModel.ID, newModel, (m) => m.Name); -// AddData(newModel.DescriptionID, newModel, (m) => m.Description); -// foreach (var work in newModel.Works) -// AddData(work.ID, work, (m) => m.Name); -// } -// else if (e.Action is NotifyCollectionChangedAction.Remove) -// { -// var oldModel = (PetModel)e.OldItems[0]; -// if (oldModel.FromMain.Value) -// return; -// RemoveData(oldModel.ID, oldModel, (m) => m.Name); -// RemoveData(oldModel.DescriptionID, oldModel, (m) => m.Description); -// foreach (var work in oldModel.Works) -// RemoveData(work.ID, work, (m) => m.Name); -// } -// else if (e.Action is NotifyCollectionChangedAction.Replace) -// { -// var newModel = (PetModel)e.NewItems[0]; -// var oldModel = (PetModel)e.OldItems[0]; -// ReplaceData(newModel.ID, newModel, (m) => m.Name); -// ReplaceData(newModel.DescriptionID, newModel, (m) => m.Description); -// foreach (var work in newModel.Works) -// ReplaceData(work.ID, work, (m) => m.Name); -// } -// }; -// } -// #endregion - -// #region DatEdit -// /// -// /// 添加数据 -// /// -// /// -// /// -// /// -// /// -// private void AddData( -// TViewModel viewModel, -// Func getID, -// Action setID, -// Func getI18nData, -// Action setI18nData -// ) -// where TViewModel : I18nModel -// where TI18nModel : ObservableObjectX, new() -// { -// if (AllI18nDatas.TryGetValue(getID(viewModel), out var outData)) -// { -// AdaptMemberAttribute -// foreach (var culture in I18nHelper.Current.CultureNames.EnumerateIndex()) -// { -// if (outData.Datas[culture.Index].Group is null) -// { -// var group = new ObservableValueGroup() { outData.Datas[culture.Index] }; -// } -// outData -// .Datas[culture.Index] -// .Group!.Add(i18nValue(i18nModel.I18nDatas[culture.Value])); -// } -// } -// else -// { -// var data = new I18nData(); -// data.ID = getID(viewModel); -// foreach (var culture in I18nHelper.Current.CultureNames) -// data.Datas.Add(i18nValue(i18nModel.I18nDatas[culture])); -// I18nDatas.Add(data); -// AllI18nDatas.Add(id.Value, data); -// //id.ValueChanged += IdChange; -// } -// } - -// /// -// /// Id改变 -// /// -// /// -// /// -// private void IdChange(ObservableValue sender, ValueChangedEventArgs e) -// { -// var sourceData = AllI18nDatas[e.OldValue]; -// //sourceData.ID.Group?.Remove(sourceData.ID); //TODO -// if (AllI18nDatas.TryGetValue(e.OldValue, out var outData)) -// { -// foreach (var culture in I18nHelper.Current.CultureNames.EnumerateIndex()) -// { -// if (outData.Datas[culture.Index].Group is null) -// { -// var group = new ObservableValueGroup() { outData.Datas[culture.Index] }; -// } -// outData.Datas[culture.Index].Group!.Add(sourceData.Datas[culture.Index]); -// } -// } -// else -// { -// sourceData.ID = e.NewValue; -// AllI18nDatas.Remove(e.OldValue); -// AllI18nDatas.Add(e.NewValue, sourceData); -// } -// } - -// /// -// /// 删除I18n资源 -// /// -// /// -// /// -// /// -// /// -// private void RemoveData( -// ObservableValue id, -// I18nModel i18nModel, -// Func> i18nValue -// ) -// where T : class, new() -// { -// var data = AllI18nDatas[id.Value]; -// foreach (var culture in I18nHelper.Current.CultureNames.EnumerateIndex()) -// { -// if (data.Datas[culture.Index].Group is ObservableValueGroup group) -// { -// group.Remove(i18nValue(i18nModel.I18nDatas[culture.Value])); -// if (group.Count == 1) -// { -// group.Clear(); -// return; -// } -// } -// else -// { -// I18nDatas.Remove(data); -// AllI18nDatas.Remove(id.Value); -// return; -// } -// } -// } - -// /// -// /// 替换I18n资源 -// /// -// /// -// /// -// /// -// /// -// private void ReplaceData( -// ObservableValue id, -// I18nModel i18nModel, -// Func> i18nValue -// ) -// where T : class, new() -// { -// var data = AllI18nDatas[id.Value]; -// foreach (var culture in I18nHelper.Current.CultureNames.EnumerateIndex()) -// { -// var oldValue = data.Datas[culture.Index]; -// var newValue = i18nValue(i18nModel.I18nDatas[culture.Value]); -// if (oldValue.Group is ObservableValueGroup group) -// { -// group.Add(newValue); -// group.Remove(oldValue); -// } -// data.Datas[culture.Index] = newValue; -// } -// } -// #endregion - -// public void Close() -// { -// I18nHelper.Current.CultureNames.CollectionChanged -= CultureNames_CollectionChanged; -// foreach (var i18nData in AllI18nDatas) -// { -// foreach (var data in i18nData.Value.Datas) -// data.Group?.Clear(); -// } -// } - -// #region Event -// private void AddCulture(string culture) -// { -// CultureChanged?.Invoke(null, culture); -// } - -// private void RemoveCulture(string culture) -// { -// CultureChanged?.Invoke(culture, string.Empty); -// } - -// private void ReplaceCulture(string oldCulture, string newCulture) -// { -// CultureChanged?.Invoke(oldCulture, newCulture); -// } - -// public event EventHandler CultureChanged; -// #endregion -//} diff --git a/VPet.ModMaker/ViewModels/ModEdit/I18nEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/I18nEditWindowVM.cs new file mode 100644 index 0000000..62269e9 --- /dev/null +++ b/VPet.ModMaker/ViewModels/ModEdit/I18nEditWindowVM.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HKW.HKWUtils.Extensions; +using HKW.HKWUtils.Observable; +using Mapster; +using VPet.ModMaker.Models; + +namespace VPet.ModMaker.ViewModels.ModEdit.I18nEdit; + +public class I18nEditWindowVM : ObservableObjectX +{ + public I18nEditWindowVM() + { + SearchTarget = SearchTargets.First(); + PropertyChanged += I18nEditWindowVM_PropertyChanged; + + ModInfoModel.Current.I18nResource.Cultures.SetChanged -= Cultures_SetChanged; + ModInfoModel.Current.I18nResource.Cultures.SetChanged += Cultures_SetChanged; + + I18nDatas = new() { Filter = DataFilter, FilteredList = [] }; + foreach (var data in ModInfoModel.Current.I18nResource.CultureDatas.Values) + I18nDatas.Add(data); + foreach (var culture in ModInfoModel.Current.I18nResource.Cultures) + SearchTargets.Add(culture.Name); + } + + #region Search + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _search = string.Empty; + + /// + /// 搜索 + /// + public string Search + { + get => _search; + set => SetProperty(ref _search, value); + } + #endregion + + /// + /// 全部I18n资源 + /// + /// (ID, (CultureName, Value)) + /// + /// + public ObservableFilterList< + ObservableCultureDataDictionary, + ObservableList> + > I18nDatas { get; } = null!; + + /// + /// 搜索目标列表 + /// + public ObservableSet SearchTargets { get; } = [nameof(ModInfoModel.ID)]; + + /// + /// 搜索目标 + /// + #region SearchTarget + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string _searchTarget = string.Empty; + + public string SearchTarget + { + get => _searchTarget; + set => SetProperty(ref _searchTarget, value); + } + #endregion + + private bool DataFilter(ObservableCultureDataDictionary item) + { + if (SearchTarget == nameof(ModInfoModel.ID)) + { + // 如果是ID则搜索ID + return item.Key.Contains(Search, StringComparison.OrdinalIgnoreCase); + } + else + { + // 如果是I18n数据则搜索对应文化 + if (item.TryGetValue(CultureInfo.GetCultureInfo(SearchTarget), out var data)) + { + return data.Contains(Search, StringComparison.OrdinalIgnoreCase); + } + return false; + } + } + + private void Cultures_SetChanged( + IObservableSet sender, + NotifySetChangedEventArgs e + ) + { + if (e.Action is SetChangeAction.Add) + { + if (e.NewItems is null) + return; + foreach (var item in e.NewItems) + { + AddCulture(item.Name); + SearchTargets.Add(item.Name); + } + } + else if (e.Action is SetChangeAction.Remove) + { + if (e.OldItems is null) + return; + foreach (var item in e.OldItems) + { + RemoveCulture(item.Name); + SearchTargets.Remove(item.Name); + } + } + } + + private void I18nEditWindowVM_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Search)) + { + I18nDatas.Refresh(); + } + else if (e.PropertyName == nameof(SearchTarget)) + { + I18nDatas.Refresh(); + } + } + + #region Event + private void AddCulture(string culture) + { + CultureChanged?.Invoke(string.Empty, culture); + } + + private void RemoveCulture(string culture) + { + CultureChanged?.Invoke(culture, string.Empty); + } + + private void ReplaceCulture(string oldCulture, string newCulture) + { + CultureChanged?.Invoke(oldCulture, newCulture); + } + + public event CultureChangedEventHandler? CultureChanged; + #endregion +} + +public delegate void CultureChangedEventHandler(string oldCulture, string newCulture); diff --git a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs index edaa7cb..ecd2bfb 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/ModEditWindowVM.cs @@ -27,8 +27,6 @@ public class ModEditWindowVM : ObservableObjectX { public ModEditWindowVM(ModEditWindow window) { - //TODO - //I18nEditWindow.Initialize(); ModEditWindow = window; ChangeImageCommand.ExecuteCommand += ChangeImageCommand_ExecuteCommand; AddCultureCommand.ExecuteCommand += AddCultureCommand_ExecuteCommand; @@ -123,8 +121,7 @@ public class ModEditWindowVM : ObservableObjectX private void EditI18nCommand_ExecuteCommand() { - I18nEditWindow.Current.Visibility = Visibility.Visible; - I18nEditWindow.Current.Activate(); + ModEditWindow.I18nEditWindow.ShowOrActivate(); } /// @@ -133,7 +130,6 @@ public class ModEditWindowVM : ObservableObjectX public void Close() { ModInfo.Image?.StreamSource?.Close(); - I18nEditWindow.Current?.Close(true); } /// diff --git a/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs b/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs index 1b09f4f..fbce0c3 100644 --- a/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModEdit/SaveTranslationModWindowVM.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -38,22 +39,20 @@ public class SaveTranslationModWindowVM : ObservableObjectX public SaveTranslationModWindowVM() { - //TODO - //foreach (var culture in I18nHelper.Current.CultureNames) - //{ - // var model = new CheckCultureModel(); - // model.CultureName.Value = culture; - // CheckCultures.Add(model); - // CheckAll.AddNotifySender(model.IsChecked); - //} - //CheckAll.ValueChanged += CheckAll_ValueChanged; - //CheckAll.SenderPropertyChanged += CheckAll_SenderPropertyChanged; - //SaveCommand.ExecuteCommand += Save; + foreach (var culture in ModInfoModel.Current.I18nResource.Cultures) + { + var model = new CheckCultureModel(culture); + model.Culture = culture; + model.PropertyChangedX += Model_PropertyChangedX; + CheckCultures.Add(model); + } + PropertyChangedX += SaveTranslationModWindowVM_PropertyChangedX; + SaveCommand.ExecuteCommand += Save; } - private void CheckAll_ValueChanged( - ObservableValue sender, - ValueChangedEventArgs e + private void SaveTranslationModWindowVM_PropertyChangedX( + object? sender, + PropertyChangedXEventArgs e ) { if (e.NewValue is null) @@ -65,25 +64,21 @@ public class SaveTranslationModWindowVM : ObservableObjectX return; } foreach (var model in CheckCultures) - model.IsChecked = e.NewValue.Value; + model.IsChecked = e.NewValue is true; } - private void CheckAll_SenderPropertyChanged( - ObservableValue source, - INotifyPropertyChanged sender - ) + private void Model_PropertyChangedX(object? sender, PropertyChangedXEventArgs e) { var count = 0; foreach (var model in CheckCultures) if (model.IsChecked) count += 1; - if (count == CheckCultures.Count) - source.Value = true; + CheckAll = true; else if (count == 0) - source.Value = false; + CheckAll = false; else - source.Value = null; + CheckAll = null; } public void Save() @@ -100,8 +95,8 @@ public class SaveTranslationModWindowVM : ObservableObjectX try { ModInfoModel.Current.SaveTranslationMod( - Path.GetDirectoryName(saveFileDialog.FileName), - CheckCultures.Where(m => m.IsChecked).Select(m => m.CultureName) + Path.GetDirectoryName(saveFileDialog.FileName)!, + CheckCultures.Where(m => m.IsChecked).Select(m => m.Culture) ); MessageBox.Show("保存成功".Translate()); } @@ -114,6 +109,12 @@ public class SaveTranslationModWindowVM : ObservableObjectX public class CheckCultureModel : ObservableObjectX { + public CheckCultureModel(CultureInfo culture) + { + _culture = culture; + Culture = culture; + } + #region IsChecked [DebuggerBrowsable(DebuggerBrowsableState.Never)] private bool _isChecked; @@ -126,12 +127,13 @@ public class CheckCultureModel : ObservableObjectX #endregion #region CultureName [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string _cultureName = string.Empty; + private CultureInfo _culture; - public string CultureName + public CultureInfo Culture { - get => _cultureName; - set => SetProperty(ref _cultureName, value); + get => _culture; + set => SetProperty(ref _culture, value); } + #endregion } diff --git a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs index 4c0fffd..af2fade 100644 --- a/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs +++ b/VPet.ModMaker/ViewModels/ModMakerWindowVM.cs @@ -304,9 +304,7 @@ public class ModMakerWindowVM : ObservableObjectX ModEditWindow?.Close(); ModEditWindow = null!; ModInfoModel.Current?.Close(); - I18nEditWindow.Current?.Close(true); - ModMakerWindow.Show(); - ModMakerWindow.Activate(); + ModMakerWindow.ShowOrActivate(); MessageBox.Show(ModMakerWindow, "模组载入失败:\n{0}".Translate(ex)); GC.Collect(); } diff --git a/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs b/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs index 9a9e6ce..06a5c75 100644 --- a/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs +++ b/VPet.ModMaker/Views/ModEdit/AddCultureWindow.xaml.cs @@ -53,7 +53,7 @@ public partial class AddCultureWindow : WindowX return; } if ( - ModInfoModel.Current.I18nResource.CultureDatas.ContainsKey( + ModInfoModel.Current.I18nResource.Cultures.Contains( CultureInfo.GetCultureInfo(ViewModel.Culture) ) ) @@ -65,10 +65,30 @@ public partial class AddCultureWindow : WindowX Close(); } + public const string CultureLink = + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c"; + private void Hyperlink_Click(object? sender, RoutedEventArgs e) { - NativeUtils.OpenLink( - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c" - ); + try + { + NativeUtils.OpenLink(CultureLink); + } + catch + { + if ( + MessageBoxX.Show( + this, + "无法正确打开链接,需要复制自行访问吗", + "", + MessageBoxButton.YesNo, + MessageBoxIcon.Warning + ) + is not MessageBoxResult.Yes + ) + return; + Clipboard.SetText(CultureLink); + MessageBoxX.Show(this, "已复制到剪贴板".Translate()); + } } } diff --git a/VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml b/VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml similarity index 90% rename from VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml rename to VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml index bf0b47d..2314557 100644 --- a/VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml +++ b/VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml @@ -27,7 +27,6 @@ @@ -52,12 +51,12 @@ Width="300" MinWidth="200" MaxWidth="500" - Binding="{Binding Id}" + Binding="{Binding Key}" CanUserSort="True" ElementStyle="{StaticResource TextBlock_Wrap}" - Header="Id" + Header="ID" IsReadOnly="True" - SortMemberPath="Id" /> + SortMemberPath="Key" /> diff --git a/VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml.cs b/VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml.cs similarity index 50% rename from VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml.cs rename to VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml.cs index 2276b8f..d23ab16 100644 --- a/VPet.ModMaker/Views/ModEdit/I18nEdit/I18nEditWindow.xaml.cs +++ b/VPet.ModMaker/Views/ModEdit/I18nEditWindow.xaml.cs @@ -21,63 +21,30 @@ public partial class I18nEditWindow : WindowX { public bool IsCancel { get; private set; } = true; - public static I18nEditWindow Current { get; private set; } = null!; - public I18nEditWindowVM ViewModel => (I18nEditWindowVM)DataContext; public I18nEditWindow() { - // 只隐藏, 不关闭 - Closing += (s, e) => - { - Hide(); - if (_close is false) - e.Cancel = true; - }; - Closed += (s, e) => - { - //TODO - //ViewModel.Close(); - try - { - DataContext = null; - Current = null; - } - catch { } - }; InitializeComponent(); - DataContext = new I18nEditWindowVM(); - //TODO - //ViewModel.CultureChanged += ViewModel_CultureChanged; - //ViewModel.InitializeI18nData(ModInfoModel.Current); + this.SetDataContext(); + this.SetCloseState(WindowCloseState.Collapsed); + foreach (var culture in ModInfoModel.Current.I18nResource.Cultures) + AddCulture(culture.Name); + ViewModel.CultureChanged += ViewModel_CultureChanged; } - public static void Initialize() + private void ViewModel_CultureChanged(string oldCultureName, string newCultureName) { - Current = new(); - } - - private bool _close = false; - - public void Close(bool close) - { - _close = close; - Close(); - } - - private void ViewModel_CultureChanged(object? sender, string newCulture) - { - var oldCulture = sender as string; - if (string.IsNullOrEmpty(oldCulture)) - AddCulture(newCulture); - else if (string.IsNullOrEmpty(newCulture)) - RemoveCulture(oldCulture); + if (string.IsNullOrEmpty(oldCultureName)) + AddCulture(newCultureName); + else if (string.IsNullOrEmpty(newCultureName)) + RemoveCulture(oldCultureName); else - ReplaceCulture(oldCulture, newCulture); + ReplaceCulture(oldCultureName, newCultureName); } #region CultureEdit - private const string ValueBindingFormat = "Datas[{0}].Value"; + private const string ValueBindingFormat = "[{0}]"; /// /// (culture, Column) @@ -87,36 +54,27 @@ public partial class I18nEditWindow : WindowX /// /// 添加文化列 /// - /// - public void AddCulture(string culture) + /// + public void AddCulture(string cultureName) { - var dataPath = string.Format(ValueBindingFormat, culture); + var dataPath = string.Format(ValueBindingFormat, cultureName); // 文化数据列 - var column = new DataGridTextColumn() - { - Width = 300, - MinWidth = 100, - MaxWidth = 500, - Header = culture, - Binding = new Binding(dataPath) { Mode = BindingMode.TwoWay }, - ElementStyle = (Style)ModMakerInfo.NativeStyles["TextBlock_Wrap"], - SortMemberPath = dataPath - }; + var column = CreateColumn(cultureName, dataPath); DataGrid_Datas.Columns.Add(column); - _dataGridI18nColumns.Add(culture, column); + _dataGridI18nColumns.Add(cultureName, column); } /// /// 删除文化列 /// - /// - public void RemoveCulture(string culture) + /// + public void RemoveCulture(string cultureName) { - DataGrid_Datas.Columns.Remove(_dataGridI18nColumns[culture]); - _dataGridI18nColumns.Remove(culture); + DataGrid_Datas.Columns.Remove(_dataGridI18nColumns[cultureName]); + _dataGridI18nColumns.Remove(cultureName); foreach (var columnData in _dataGridI18nColumns) { - var dataPath = string.Format(ValueBindingFormat, culture); + var dataPath = string.Format(ValueBindingFormat, cultureName); columnData.Value.Binding = new Binding(dataPath) { Mode = BindingMode.TwoWay }; columnData.Value.SortMemberPath = dataPath; } @@ -125,16 +83,31 @@ public partial class I18nEditWindow : WindowX /// /// 替换文化列 /// - /// - /// - public void ReplaceCulture(string oldCulture, string newCulture) + /// + /// + public void ReplaceCulture(string oldCultureName, string newCultureName) { //if (_dataGridI18nColumns.ContainsKey(newCultureName)) // throw new(); - var column = _dataGridI18nColumns[oldCulture]; - column.Header = newCulture; - _dataGridI18nColumns.Remove(oldCulture); - _dataGridI18nColumns.Add(newCulture, column); + var column = _dataGridI18nColumns[oldCultureName]; + column.Header = newCultureName; + _dataGridI18nColumns.Remove(oldCultureName); + _dataGridI18nColumns.Add(newCultureName, column); + } + + public static DataGridTextColumn CreateColumn(string header, string dataPath) + { + return new DataGridTextColumn() + { + Width = 300, + MinWidth = 100, + MaxWidth = 500, + Header = header, + Binding = new Binding(dataPath) { Mode = BindingMode.TwoWay }, + ElementStyle = (Style)ModMakerInfo.NativeStyles["TextBlock_Wrap"], + SortMemberPath = dataPath, + CanUserSort = true + }; } #endregion diff --git a/VPet.ModMaker/Views/ModEdit/ModEditWindow.xaml b/VPet.ModMaker/Views/ModEdit/ModEditWindow.xaml index 15bc053..10f84e7 100644 --- a/VPet.ModMaker/Views/ModEdit/ModEditWindow.xaml +++ b/VPet.ModMaker/Views/ModEdit/ModEditWindow.xaml @@ -279,7 +279,7 @@ x:Name="ListBox_Cultures" Grid.Row="1" d:ItemsSource="{d:SampleData ItemCount=5}" - ItemsSource="{Binding I18nResource.CultureDatas.ObservableKeys}" + ItemsSource="{Binding I18nResource.Cultures}" ScrollViewer.VerticalScrollBarVisibility="Auto" SelectedItem="{Binding I18nResource.CurrentCulture}"> @@ -311,7 +311,6 @@