This commit is contained in:
Hakoyu
2023-10-18 23:54:36 +08:00
parent 9f361f1bab
commit 58fe49abc6
19 changed files with 647 additions and 301 deletions

View File

@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace VPet.ModMaker.Converters;
@ -38,6 +39,8 @@ public class CalculatorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Any(i => i == DependencyProperty.UnsetValue))
return 0;
if (values.Length == 1)
return values[0];
double result = System.Convert.ToDouble(values[0]);

View File

@ -29,6 +29,8 @@ public class RatioMarginConverter : IMultiValueConverter
System.Globalization.CultureInfo culture
)
{
if (values.Any(i => i == DependencyProperty.UnsetValue))
return new Thickness();
if (values.Length == 0)
{
return new Thickness();

View File

@ -142,6 +142,26 @@ public class AnimeTypeModel
}
}
public void Close()
{
foreach (var anime in HappyAnimes)
anime.Close();
foreach (var anime in NomalAnimes)
anime.Close();
foreach (var anime in PoorConditionAnimes)
anime.Close();
foreach (var anime in IllAnimes)
anime.Close();
}
public void Clear()
{
HappyAnimes.Clear();
NomalAnimes.Clear();
PoorConditionAnimes.Clear();
IllAnimes.Clear();
}
public AnimeTypeModel(GraphInfo.GraphType graphType, string path)
{
Name.Value = Path.GetFileName(path);

View File

@ -57,9 +57,9 @@ public class FoodAnimeModel
double.Parse(infos[3])
);
}
if (infos.Length > 3)
foodLocationInfo.Rotate.Value = double.Parse(infos[4]);
if (infos.Length > 4)
foodLocationInfo.Rotate.Value = double.Parse(infos[4]);
if (infos.Length > 5)
foodLocationInfo.Opacity.Value = double.Parse(infos[5]);
FoodLocations.Add(foodLocationInfo);
}

View File

@ -15,6 +15,17 @@ namespace VPet.ModMaker.Models.ModModel;
public class FoodAnimeTypeModel
{
/// <summary>
/// 动作类型
/// </summary>
public static GraphInfo.GraphType GraphType => GraphInfo.GraphType.Common;
/// <summary>
/// 动画名称
/// </summary>
public static HashSet<string> FoodAnimeNames =
new(StringComparer.InvariantCultureIgnoreCase) { "Eat", "Drink", "Gift", };
/// <summary>
/// Id
/// </summary>
@ -25,11 +36,6 @@ public class FoodAnimeTypeModel
/// </summary>
public ObservableValue<string> Name { get; } = new();
/// <summary>
/// 动作类型
/// </summary>
public GraphInfo.GraphType GraphType => GraphInfo.GraphType.Common;
/// <summary>
/// 开心动画
/// </summary>
@ -53,10 +59,30 @@ public class FoodAnimeTypeModel
public FoodAnimeTypeModel()
{
HappyAnimes.CollectionChanged += Animes_CollectionChanged;
//Name.ValueChanged += (_, _) =>
//{
// Id.Value = $"{GraphType.Value}_{Name.Value}";
//};
Name.ValueChanged += (_, _) =>
{
Id.Value = $"{GraphType}_{Name.Value}";
};
}
public void Close()
{
foreach (var anime in HappyAnimes)
anime.Close();
foreach (var anime in NomalAnimes)
anime.Close();
foreach (var anime in PoorConditionAnimes)
anime.Close();
foreach (var anime in IllAnimes)
anime.Close();
}
public void Clear()
{
HappyAnimes.Clear();
NomalAnimes.Clear();
PoorConditionAnimes.Clear();
IllAnimes.Clear();
}
private void Animes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@ -157,16 +183,16 @@ public class FoodAnimeTypeModel
public void ParseInfoFile(string path, string infoPath)
{
var lps = new LPS(infoPath);
var foodAnimeInfos = lps.FindAllLineInfo(nameof(FoodAnimation));
var lps = new LPS(File.ReadAllText(infoPath));
var foodAnimeInfos = lps.FindAllLine(nameof(FoodAnimation));
if (foodAnimeInfos.Any() is false)
throw new Exception("信息文件\n{0}\n未包含食物动画信息".Translate(infoPath));
var pngAnimeInfos = lps.FindAllLineInfo(nameof(PNGAnimation))
var pngAnimeInfos = lps.FindAllLine(nameof(PNGAnimation))
.Select(
i =>
new PNGAnimeInfo(
i.Info,
i.Find("infoPath").Info,
i.Find("path").Info,
(GameSave.ModeType)
Enum.Parse(typeof(GameSave.ModeType), i.Find("mode").Info, true)
)
@ -246,7 +272,7 @@ public class FoodAnimeTypeModel
i =>
new ImageModel(
Utils.LoadImageToMemoryStream(i),
int.Parse(Path.GetFileNameWithoutExtension(i).Split('_')[1])
int.Parse(Path.GetFileNameWithoutExtension(i).Split('_')[2])
)
)
);

View File

@ -31,7 +31,7 @@ public class ImageModel
public ImageModel Copy()
{
var model = new ImageModel(Image.Value, Duration.Value);
var model = new ImageModel(Image.Value.Copy(), Duration.Value);
return model;
}

View File

@ -236,6 +236,11 @@ public class ModInfoModel : I18nModel<I18nModInfoModel>
)
petModel.Animes.Add(model1);
}
else if (FoodAnimeTypeModel.FoodAnimeNames.Contains(dirName))
{
//if (FoodAnimeTypeModel.Create(animeDir) is FoodAnimeTypeModel model1)
// petModel.FoodAnimes.Add(model1);
}
}
}

View File

@ -50,7 +50,6 @@ public static class Utils
{
BitmapImage bitmapImage = new();
bitmapImage.BeginInit();
bitmapImage.DecodePixelWidth = DecodePixelWidth;
try
{
var ms = new MemoryStream();
@ -62,6 +61,8 @@ public static class Utils
{
bitmapImage.EndInit();
}
if (bitmapImage.PixelWidth > DecodePixelWidth)
bitmapImage.DecodePixelWidth = DecodePixelWidth;
return bitmapImage;
}
}

View File

@ -13,7 +13,7 @@ namespace HKW.HKWViewModels.SimpleObservable;
/// 可观察命令
/// </summary>
[DebuggerDisplay(
"CanExecute = {CanExecuteProperty.EnumValue}, EventCount = {ExecuteEvent.GetInvocationList().Length}, AsyncEventCount = {AsyncExecuteEvent.GetInvocationList().Length}"
"CanExecute = {CanExecuteProperty.Value}, EventCount = {ExecuteEvent.GetInvocationList().Length}, AsyncEventCount = {AsyncExecuteEvent.GetInvocationList().Length}"
)]
public class ObservableCommand : ICommand
{
@ -23,16 +23,23 @@ public class ObservableCommand : ICommand
public ObservableValue<bool> CanExecuteProperty { get; } = new(true);
/// <summary>
/// 等待异步执行完成
/// 当前可执行状态
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ObservableValue<bool> r_waiting = new(false);
public ObservableValue<bool> CurrentCanExecute { get; } = new(true);
/// <inheritdoc/>
public ObservableCommand()
{
CanExecuteProperty.PropertyChanged += InvokeCanExecuteChanged;
r_waiting.PropertyChanged += InvokeCanExecuteChanged;
CurrentCanExecute.PropertyChanged += InvokeCanExecuteChanged;
CurrentCanExecute.ValueChanging += CurrentCanExecute_ValueChanging;
}
private bool CurrentCanExecute_ValueChanging(bool oldValue, bool newValue)
{
if (newValue is true && CanExecuteProperty.Value is false)
return true;
return false;
}
private void InvokeCanExecuteChanged(object? sender, PropertyChangedEventArgs e)
@ -48,9 +55,7 @@ public class ObservableCommand : ICommand
/// <returns>能被执行为 <see langword="true"/> 否则为 <see langword="false"/></returns>
public bool CanExecute(object? parameter)
{
if (r_waiting.Value is true)
return false;
return CanExecuteProperty.Value;
return CurrentCanExecute.Value && CanExecuteProperty.Value;
}
/// <summary>
@ -71,12 +76,12 @@ public class ObservableCommand : ICommand
{
if (AsyncExecuteEvent is null)
return;
r_waiting.Value = true;
CurrentCanExecute.Value = false;
foreach (
var asyncEvent in AsyncExecuteEvent.GetInvocationList().Cast<AsyncExecuteHandler>()
)
await asyncEvent.Invoke();
r_waiting.Value = false;
CurrentCanExecute.Value = true;
}
#endregion

View File

@ -14,7 +14,7 @@ namespace HKW.HKWViewModels.SimpleObservable;
/// </summary>
/// <typeparam name="T">参数类型</typeparam>
[DebuggerDisplay(
"CanExecute = {CanExecuteProperty.EnumValue}, EventCount = {ExecuteEvent.GetInvocationList().Length}, AsyncEventCount = {AsyncExecuteEvent.GetInvocationList().Length}"
"CanExecute = {CanExecuteProperty.Value}, EventCount = {ExecuteEvent.GetInvocationList().Length}, AsyncEventCount = {AsyncExecuteEvent.GetInvocationList().Length}"
)]
public class ObservableCommand<T> : ICommand
where T : notnull
@ -22,15 +22,24 @@ public class ObservableCommand<T> : ICommand
/// <inheritdoc cref="ObservableCommand.CanExecuteProperty"/>
public ObservableValue<bool> CanExecuteProperty { get; } = new(true);
/// <inheritdoc cref="ObservableCommand.r_waiting"/>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly ObservableValue<bool> r_waiting = new(false);
/// <summary>
/// 当前可执行状态
/// </summary>
public ObservableValue<bool> CurrentCanExecute { get; } = new(true);
/// <inheritdoc />
/// <inheritdoc/>
public ObservableCommand()
{
CanExecuteProperty.PropertyChanged += InvokeCanExecuteChanged;
r_waiting.PropertyChanged += InvokeCanExecuteChanged;
CurrentCanExecute.PropertyChanged += InvokeCanExecuteChanged;
CurrentCanExecute.ValueChanging += CurrentCanExecute_ValueChanging;
}
private bool CurrentCanExecute_ValueChanging(bool oldValue, bool newValue)
{
if (newValue is true && CanExecuteProperty.Value is false)
return true;
return false;
}
private void InvokeCanExecuteChanged(object? sender, PropertyChangedEventArgs e)
@ -42,9 +51,7 @@ public class ObservableCommand<T> : ICommand
/// <inheritdoc cref="ObservableCommand.CanExecute(object?)"/>
public bool CanExecute(object? parameter)
{
if (r_waiting.Value is true)
return false;
return CanExecuteProperty.Value;
return CurrentCanExecute.Value && CanExecuteProperty.Value;
}
/// <inheritdoc cref="ObservableCommand.Execute(object?)"/>
@ -60,12 +67,12 @@ public class ObservableCommand<T> : ICommand
{
if (AsyncExecuteEvent is null)
return;
r_waiting.Value = true;
CurrentCanExecute.Value = false;
foreach (
var asyncEvent in AsyncExecuteEvent.GetInvocationList().Cast<AsyncExecuteHandler>()
)
await asyncEvent.Invoke(parameter);
r_waiting.Value = false;
CurrentCanExecute.Value = true;
}
#endregion

View File

@ -28,9 +28,11 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
{
if (_value?.Equals(value) is true)
return;
NotifyPropertyChanging(_value, value);
var oldValue = _value;
if (NotifyPropertyChanging(oldValue, value))
return;
_value = value;
NotifyPropertyChanged(_value, value);
NotifyPropertyChanged(oldValue, value);
}
}
@ -57,10 +59,15 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
/// </summary>
/// <param name="oldValue">旧值</param>
/// <param name="newValue">新值</param>
private void NotifyPropertyChanging(T oldValue, T newValue)
private bool NotifyPropertyChanging(T oldValue, T newValue)
{
PropertyChanging?.Invoke(this, new(nameof(Value)));
ValueChanging?.Invoke(oldValue, newValue);
// 若全部事件取消改变 则取消改变
return ValueChanging
?.GetInvocationList()
.Cast<ValueChangingEventHandler>()
.All(e => e.Invoke(oldValue, newValue) is true)
is true;
}
/// <summary>
@ -98,8 +105,8 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
/// {
/// v = "B"; // trigger this
/// };
/// value1.EnumValue = "A"; // execute this
/// // result: value1.EnumValue == "A" , value2.EnumValue == "B"
/// value1.Value = "A"; // execute this
/// // result: value1.Value == "A" , value2.Value == "B"
/// ]]>
/// </code></para>
/// </summary>
@ -142,12 +149,12 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
/// <summary>
/// 值改变前事件
/// </summary>
public event ValueChangeEventHandler? ValueChanging;
public event ValueChangingEventHandler? ValueChanging;
/// <summary>
/// 值改变后事件
/// </summary>
public event ValueChangeEventHandler? ValueChanged;
public event ValueChangedEventHandler? ValueChanged;
/// <summary>
/// 通知接收器事件
@ -161,7 +168,15 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
/// </summary>
/// <param name="oldValue">旧值</param>
/// <param name="newValue">新值</param>
public delegate void ValueChangeEventHandler(T oldValue, T newValue);
/// <returns>取消改变</returns>
public delegate bool ValueChangingEventHandler(T oldValue, T newValue);
/// <summary>
/// 值改变后事件
/// </summary>
/// <param name="oldValue">旧值</param>
/// <param name="newValue">新值</param>
public delegate void ValueChangedEventHandler(T oldValue, T newValue);
/// <summary>
/// 通知接收器

View File

@ -3,12 +3,14 @@ using LinePutScript.Localization.WPF;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using VPet.ModMaker.Models;
using VPet.ModMaker.Models.ModModel;
using VPet_Simulator.Core;
@ -74,24 +76,34 @@ public class AnimeEditWindowVM
public ObservableCommand StopCommand { get; } = new();
/// <summary>
/// 添加图片命令
/// 添加动画命令
/// </summary>
public ObservableCommand<AnimeModel> AddImageCommand { get; } = new();
/// <summary>
/// 清除图片命令
/// </summary>
public ObservableCommand<AnimeModel> ClearImageCommand { get; } = new();
public ObservableCommand AddAnimeCommand { get; } = new();
/// <summary>
/// 删除动画命令
/// </summary>
public ObservableCommand<AnimeModel> RemoveAnimeCommand { get; } = new();
/// <summary>
/// 添加图片命令
/// </summary>
public ObservableCommand<AnimeModel> AddImageCommand { get; } = new();
/// <summary>
/// 删除图片命令
/// </summary>
public ObservableCommand<AnimeModel> RemoveImageCommand { get; } = new();
/// <summary>
/// 替换图片命令
/// </summary>
public ObservableCommand<AnimeModel> ChangeImageCommand { get; } = new();
/// <summary>
/// 清除图片命令
/// </summary>
public ObservableCommand<AnimeModel> ClearImageCommand { get; } = new();
#endregion
/// <summary>
@ -110,12 +122,14 @@ public class AnimeEditWindowVM
CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged;
PlayCommand.ExecuteEvent += PlayCommand_ExecuteEvent;
PlayCommand.AsyncExecuteEvent += PlayCommand_AsyncExecuteEvent;
StopCommand.ExecuteEvent += StopCommand_ExecuteEvent;
AddImageCommand.ExecuteEvent += AddImageCommand_ExecuteEvent;
ClearImageCommand.ExecuteEvent += ClearImageCommand_ExecuteEvent;
AddAnimeCommand.ExecuteEvent += AddAnimeCommand_ExecuteEvent;
RemoveAnimeCommand.ExecuteEvent += RemoveAnimeCommand_ExecuteEvent;
AddImageCommand.ExecuteEvent += AddImageCommand_ExecuteEvent;
RemoveImageCommand.ExecuteEvent += RemoveImageCommand_ExecuteEvent;
ChangeImageCommand.ExecuteEvent += ChangeImageCommand_ExecuteEvent;
ClearImageCommand.ExecuteEvent += ClearImageCommand_ExecuteEvent;
Anime.ValueChanged += Anime_ValueChanged;
}
@ -135,6 +149,24 @@ public class AnimeEditWindowVM
HasAnimeName.Value = true;
}
#endregion
#region AnimeCommand
/// <summary>
/// 添加动画
/// </summary>
/// <param name="value">动画模型</param>
private void AddAnimeCommand_ExecuteEvent()
{
if (CurrentMode is GameSave.ModeType.Happy)
Anime.Value.HappyAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.Nomal)
Anime.Value.NomalAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.PoorCondition)
Anime.Value.PoorConditionAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.Ill)
Anime.Value.IllAnimes.Add(new());
}
/// <summary>
/// 删除动画
/// </summary>
@ -157,6 +189,64 @@ public class AnimeEditWindowVM
value.Close();
}
}
#endregion
#region ImageCommand
/// <summary>
/// 添加图片
/// </summary>
/// <param name="value">动画模型</param>
private void AddImageCommand_ExecuteEvent(AnimeModel value)
{
OpenFileDialog openFileDialog =
new()
{
Title = "选择图片".Translate(),
Filter = $"图片|*.png".Translate(),
Multiselect = true
};
if (openFileDialog.ShowDialog() is not true)
return;
AddImages(value.Images, openFileDialog.FileNames);
}
/// <summary>
/// 删除图片
/// </summary>
/// <param name="value">动画模型</param>
private void RemoveImageCommand_ExecuteEvent(AnimeModel value)
{
value.Images.Remove(CurrentImageModel.Value);
CurrentImageModel.Value.Close();
}
/// <summary>
/// 替换图片
/// </summary>
/// <param name="value"></param>
/// <exception cref="NotImplementedException"></exception>
private void ChangeImageCommand_ExecuteEvent(AnimeModel value)
{
OpenFileDialog openFileDialog =
new() { Title = "选择图片".Translate(), Filter = $"图片|*.png".Translate() };
if (openFileDialog.ShowDialog() is not true)
return;
BitmapImage newImage;
try
{
newImage = Utils.LoadImageToMemoryStream(openFileDialog.FileName);
}
catch (Exception ex)
{
MessageBox.Show("替换失败失败 \n{0}".Translate(ex));
return;
}
if (newImage is null)
return;
CurrentImageModel.Value.Close();
CurrentImageModel.Value.Image.Value = newImage;
}
/// <summary>
/// 清空图片
@ -176,57 +266,36 @@ public class AnimeEditWindowVM
/// <summary>
/// 添加图片
/// </summary>
/// <param name="value">动画模型</param>
private void AddImageCommand_ExecuteEvent(AnimeModel value)
{
OpenFileDialog openFileDialog =
new() { Title = "选择图片".Translate(), Filter = $"图片|*.png".Translate() };
if (openFileDialog.ShowDialog() is true)
{
value.Images.Add(new(Utils.LoadImageToMemoryStream(openFileDialog.FileName)));
}
}
/// <summary>
/// 添加图片
/// </summary>
/// <param name="model">动画模型</param>
/// <param name="images">动画</param>
/// <param name="paths">路径</param>
public void AddImages(AnimeModel model, IEnumerable<string> paths)
public void AddImages(ObservableCollection<ImageModel> images, IEnumerable<string> paths)
{
try
{
var newImages = new List<ImageModel>();
foreach (string path in paths)
{
if (File.Exists(path))
{
model.Images.Add(new(Utils.LoadImageToMemoryStream(path)));
newImages.Add(new(Utils.LoadImageToMemoryStream(path)));
}
else if (Directory.Exists(path))
{
foreach (var file in Directory.EnumerateFiles(path, "*.png"))
{
model.Images.Add(new(Utils.LoadImageToMemoryStream(path)));
newImages.Add(new(Utils.LoadImageToMemoryStream(path)));
}
}
}
foreach (var image in newImages)
images.Add(image);
}
catch (Exception ex)
{
MessageBox.Show("添加失败 \n{0}".Translate(ex));
}
}
/// <summary>
/// 删除图片
/// </summary>
/// <param name="value">动画模型</param>
private void RemoveImageCommand_ExecuteEvent(AnimeModel value)
{
CurrentImageModel.Value.Close();
value.Images.Remove(CurrentImageModel.Value);
}
#endregion
#region Player
private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue)
{
@ -249,19 +318,13 @@ public class AnimeEditWindowVM
{
if (_playing is false)
return;
Reset();
}
/// <summary>
/// 开始播放
/// </summary>
private void PlayCommand_ExecuteEvent()
private async Task PlayCommand_AsyncExecuteEvent()
{
if (_playing)
{
MessageBox.Show("正在播放".Translate());
return;
}
if (CurrentAnimeModel.Value is null)
{
MessageBox.Show("未选中动画".Translate());
@ -269,6 +332,8 @@ public class AnimeEditWindowVM
}
_playing = true;
_playerTask.Start();
await Task.WhenAll(_playerTask);
Reset();
}
/// <summary>

View File

@ -61,12 +61,12 @@ public class AnimePageVM
/// <summary>
/// 编辑命令
/// </summary>
public ObservableCommand<AnimeTypeModel> EditCommand { get; } = new();
public ObservableCommand<object> EditCommand { get; } = new();
/// <summary>
/// 删除命令
/// </summary>
public ObservableCommand<AnimeTypeModel> RemoveCommand { get; } = new();
public ObservableCommand<object> RemoveCommand { get; } = new();
#endregion
public AnimePageVM()
{
@ -143,43 +143,83 @@ public class AnimePageVM
selectGraphTypeWindow.CurrentPet.Value = CurrentPet.Value;
selectGraphTypeWindow.ShowDialog();
var graphType = selectGraphTypeWindow.GraphType.Value;
var animeName = selectGraphTypeWindow.AnimeName.Value;
if (selectGraphTypeWindow.IsCancel)
return;
// TODO: FoodAnime
var window = new AnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.Anime.Value.GraphType.Value = graphType;
vm.Anime.Value.Name.Value = selectGraphTypeWindow.AnimeName.Value;
window.ShowDialog();
if (window.IsCancel)
return;
Animes.Add(vm.Anime.Value);
if (
graphType is VPet_Simulator.Core.GraphInfo.GraphType.Common
&& FoodAnimeTypeModel.FoodAnimeNames.Contains(animeName)
)
{
var window = new FoodAnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.Anime.Value.Name.Value = animeName;
window.ShowDialog();
if (window.IsCancel)
return;
FoodAnimes.Add(vm.Anime.Value);
}
else
{
var window = new AnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.Anime.Value.GraphType.Value = graphType;
vm.Anime.Value.Name.Value = animeName;
window.ShowDialog();
if (window.IsCancel)
return;
Animes.Add(vm.Anime.Value);
}
}
/// <summary>
/// 编辑动画
/// </summary>
/// <param name="model">动画类型模型</param>
public void Edit(AnimeTypeModel model)
public void Edit(object model)
{
// TODO: FoodAnime
var window = new AnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.OldAnime = model;
var newAnime = vm.Anime.Value = new(model);
window.ShowDialog();
if (window.IsCancel)
return;
if (ShowAnimes.Value.Count == Animes.Count)
if (model is AnimeTypeModel animeTypeModel)
{
Animes[Animes.IndexOf(model)] = newAnime;
// TODO: FoodAnime
var window = new AnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.OldAnime = animeTypeModel;
var newAnime = vm.Anime.Value = new(animeTypeModel);
window.ShowDialog();
if (window.IsCancel)
return;
if (ShowAnimes.Value.Count == Animes.Count)
{
Animes[Animes.IndexOf(animeTypeModel)] = newAnime;
}
else
{
Animes[Animes.IndexOf(animeTypeModel)] = newAnime;
ShowAnimes.Value[ShowAnimes.Value.IndexOf(animeTypeModel)] = newAnime;
}
}
else
else if (model is FoodAnimeTypeModel foodAnimeTypeModel)
{
Animes[Animes.IndexOf(model)] = newAnime;
ShowAnimes.Value[ShowAnimes.Value.IndexOf(model)] = newAnime;
var window = new FoodAnimeEditWindow();
var vm = window.ViewModel;
vm.CurrentPet = CurrentPet.Value;
vm.OldAnime = foodAnimeTypeModel;
var newAnime = vm.Anime.Value = new(foodAnimeTypeModel);
window.ShowDialog();
if (window.IsCancel)
return;
if (ShowAnimes.Value.Count == FoodAnimes.Count)
{
FoodAnimes[FoodAnimes.IndexOf(foodAnimeTypeModel)] = newAnime;
}
else
{
FoodAnimes[FoodAnimes.IndexOf(foodAnimeTypeModel)] = newAnime;
ShowAnimes.Value[ShowAnimes.Value.IndexOf(foodAnimeTypeModel)] = newAnime;
}
}
}
@ -187,18 +227,20 @@ public class AnimePageVM
/// 删除动画
/// </summary>
/// <param name="model">动画类型模型</param>
private void Remove(AnimeTypeModel model)
private void Remove(object model)
{
if (MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.No)
return;
if (ShowAnimes.Value.Count == AllAnimes.Count)
ShowAnimes.Value.Remove(model);
if (model is AnimeTypeModel animeTypeModel)
{
AllAnimes.Remove(model);
Animes.Remove(animeTypeModel);
animeTypeModel.Close();
}
else
else if (model is FoodAnimeTypeModel foodAnimeTypeModel)
{
ShowAnimes.Value.Remove(model);
AllAnimes.Remove(model);
FoodAnimes.Remove(foodAnimeTypeModel);
foodAnimeTypeModel.Close();
}
}
}

View File

@ -3,11 +3,9 @@ using LinePutScript.Localization.WPF;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
@ -27,12 +25,15 @@ public class FoodAnimeEditWindowVM
/// <summary>
/// 默认食物图片
/// </summary>
public static BitmapImage DefaultFoodImage { get; } = Utils.LoadImageToMemoryStream("");
public static BitmapImage DefaultFoodImage { get; } =
Utils.LoadImageToMemoryStream(
"C:\\Users\\HKW\\Desktop\\TestPicture\\0000_core\\image\\food.png"
);
/// <summary>
/// 食物图片
/// </summary>
public ObservableValue<BitmapImage> FoodImage { get; } = new();
public ObservableValue<BitmapImage> FoodImage { get; } = new(DefaultFoodImage);
/// <summary>
/// 比例
@ -101,25 +102,64 @@ public class FoodAnimeEditWindowVM
public ObservableCommand StopCommand { get; } = new();
/// <summary>
/// 添加图片命令
/// 添加动画命令
/// </summary>
public ObservableCommand<AnimeModel> AddImageCommand { get; } = new();
/// <summary>
/// 清除图片命令
/// </summary>
public ObservableCommand<AnimeModel> ClearImageCommand { get; } = new();
public ObservableCommand AddAnimeCommand { get; } = new();
/// <summary>
/// 删除动画命令
/// </summary>
public ObservableCommand<AnimeModel> RemoveAnimeCommand { get; } = new();
public ObservableCommand<FoodAnimeModel> RemoveAnimeCommand { get; } = new();
#region FrontImage
/// <summary>
/// 添加顶层图片命令
/// </summary>
public ObservableCommand<FoodAnimeModel> AddFrontImageCommand { get; } = new();
/// <summary>
/// 删除图片命令
/// 删除顶层图片命令
/// </summary>
public ObservableCommand<AnimeModel> RemoveImageCommand { get; } = new();
public ObservableCommand<FoodAnimeModel> RemoveFrontImageCommand { get; } = new();
/// <summary>
/// 清除顶层图片命令
/// </summary>
public ObservableCommand<FoodAnimeModel> ClearFrontImageCommand { get; } = new();
#endregion
#region BackImage
/// <summary>
/// 添加底层图片命令
/// </summary>
public ObservableCommand<FoodAnimeModel> AddBackImageCommand { get; } = new();
/// <summary>
/// 删除底层图片命令
/// </summary>
public ObservableCommand<FoodAnimeModel> RemoveBackImageCommand { get; } = new();
/// <summary>
/// 清除底层图片命令
/// </summary>
public ObservableCommand<FoodAnimeModel> ClearBackImageCommand { get; } = new();
#endregion
#region FoodLocation
/// <summary>
/// 添加食物定位命令
/// </summary>
public ObservableCommand<FoodAnimeModel> AddeFoodLocationCommand { get; } = new();
/// <summary>
/// 删除食物定位命令
/// </summary>
public ObservableCommand<FoodAnimeModel> RemoveFoodLocationCommand { get; } = new();
/// <summary>
/// 清除食物定位命令
/// </summary>
public ObservableCommand<FoodAnimeModel> ClearFoodLocationCommand { get; } = new();
#endregion
/// <summary>
/// 改变食物图片
/// </summary>
@ -159,16 +199,25 @@ public class FoodAnimeEditWindowVM
CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged;
PlayCommand.ExecuteEvent += PlayCommand_ExecuteEvent;
PlayCommand.AsyncExecuteEvent += PlayCommand_AsyncExecuteEvent;
StopCommand.ExecuteEvent += StopCommand_ExecuteEvent;
AddImageCommand.ExecuteEvent += AddImageCommand_ExecuteEvent;
ClearImageCommand.ExecuteEvent += ClearImageCommand_ExecuteEvent;
RemoveAnimeCommand.ExecuteEvent += RemoveAnimeCommand_ExecuteEvent;
RemoveImageCommand.ExecuteEvent += RemoveImageCommand_ExecuteEvent;
ReplaceFoodImageCommand.ExecuteEvent += ReplaceFoodImageCommand_ExecuteEvent;
ReplaceFoodImageCommand.ExecuteEvent += ChangeFoodImageCommand_ExecuteEvent;
ResetFoodImageCommand.ExecuteEvent += ResetFoodImageCommand_ExecuteEvent;
Anime.ValueChanged += Anime_ValueChanged;
AddAnimeCommand.ExecuteEvent += AddAnimeCommand_ExecuteEvent;
RemoveAnimeCommand.ExecuteEvent += RemoveAnimeCommand_ExecuteEvent;
AddFrontImageCommand.ExecuteEvent += AddFrontImageCommand_ExecuteEvent;
RemoveFrontImageCommand.ExecuteEvent += RemoveFrontImageCommand_ExecuteEvent;
ClearFrontImageCommand.ExecuteEvent += ClearFrontImageCommand_ExecuteEvent;
AddBackImageCommand.ExecuteEvent += AddBackImageCommand_ExecuteEvent;
RemoveBackImageCommand.ExecuteEvent += RemoveBackImageCommand_ExecuteEvent;
ClearBackImageCommand.ExecuteEvent += ClearBackImageCommand_ExecuteEvent;
AddeFoodLocationCommand.ExecuteEvent += AddeFoodLocationCommand_ExecuteEvent;
RemoveFoodLocationCommand.ExecuteEvent += RemoveFoodLocationCommand_ExecuteEvent;
ClearFoodLocationCommand.ExecuteEvent += ClearFoodLocationCommand_ExecuteEvent;
}
private void ResetFoodImageCommand_ExecuteEvent()
@ -178,7 +227,7 @@ public class FoodAnimeEditWindowVM
FoodImage.Value = DefaultFoodImage;
}
private void ReplaceFoodImageCommand_ExecuteEvent()
private void ChangeFoodImageCommand_ExecuteEvent()
{
OpenFileDialog openFileDialog =
new() { Title = "选择食物图片".Translate(), Filter = $"图片|*.png".Translate() };
@ -190,113 +239,218 @@ public class FoodAnimeEditWindowVM
}
}
#region LoadAnime
private void Anime_ValueChanged(FoodAnimeTypeModel oldValue, FoodAnimeTypeModel newValue)
//#region LoadAnime
//private void Anime_ValueChanged(FoodAnimeTypeModel oldValue, FoodAnimeTypeModel newValue)
//{
// CheckGraphType(newValue);
//}
//private void CheckGraphType(FoodAnimeTypeModel model)
//{
// //if (FoodAnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value))
// // HasMultiType.Value = true;
// //if (FoodAnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value))
// // HasAnimeName.Value = true;
//}
//#endregion
#region AnimeCommand
private void AddAnimeCommand_ExecuteEvent()
{
CheckGraphType(newValue);
if (CurrentMode is GameSave.ModeType.Happy)
Anime.Value.HappyAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.Nomal)
Anime.Value.NomalAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.PoorCondition)
Anime.Value.PoorConditionAnimes.Add(new());
else if (CurrentMode is GameSave.ModeType.Ill)
Anime.Value.IllAnimes.Add(new());
}
private void CheckGraphType(FoodAnimeTypeModel model)
{
//if (FoodAnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value))
// HasMultiType.Value = true;
//if (FoodAnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value))
// HasAnimeName.Value = true;
}
#endregion
/// <summary>
/// 删除动画
/// </summary>
/// <param name="value">动画模型</param>
private void RemoveAnimeCommand_ExecuteEvent(AnimeModel value)
private void RemoveAnimeCommand_ExecuteEvent(FoodAnimeModel value)
{
if (
MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
)
{
//if (CurrentMode is GameSave.ModeType.Happy)
// Anime.Value.HappyAnimes.Remove(value);
//else if (CurrentMode is GameSave.ModeType.Nomal)
// Anime.Value.NomalAnimes.Remove(value);
//else if (CurrentMode is GameSave.ModeType.PoorCondition)
// Anime.Value.PoorConditionAnimes.Remove(value);
//else if (CurrentMode is GameSave.ModeType.Ill)
// Anime.Value.IllAnimes.Remove(value);
if (CurrentMode is GameSave.ModeType.Happy)
Anime.Value.HappyAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.Nomal)
Anime.Value.NomalAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.PoorCondition)
Anime.Value.PoorConditionAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.Ill)
Anime.Value.IllAnimes.Remove(value);
value.Close();
}
}
#endregion
#region ImageCommand
#region FrontImageCommand
/// <summary>
/// 添加顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void AddFrontImageCommand_ExecuteEvent(FoodAnimeModel value)
{
OpenFileDialog openFileDialog =
new()
{
Title = "选择图片".Translate(),
Filter = $"图片|*.png".Translate(),
Multiselect = true
};
if (openFileDialog.ShowDialog() is true)
{
AddImages(value.FrontImages, openFileDialog.FileNames);
}
}
/// <summary>
/// 清空图片
/// 删除顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void ClearImageCommand_ExecuteEvent(AnimeModel value)
private void RemoveFrontImageCommand_ExecuteEvent(FoodAnimeModel value)
{
value.FrontImages.Remove(CurrentFrontImageModel.Value);
CurrentFrontImageModel.Value.Close();
}
/// <summary>
/// 清空顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void ClearFrontImageCommand_ExecuteEvent(FoodAnimeModel value)
{
if (
MessageBox.Show("确定清空吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
)
{
value.Close();
value.Images.Clear();
foreach (var image in value.FrontImages)
image.Close();
value.FrontImages.Clear();
}
}
private void ShowFrontImagesPathInfo(FoodImagesPath imagesPath)
{
MessageBox.Show(
"此顶层动画源位于其它位置\n请去源位置修改此动画\n源位置 模式:{0} 索引:{1}".Translate(
imagesPath.Mode,
imagesPath.Index
)
);
}
#endregion
#region BackImageCommand
/// <summary>
/// 添加图片
/// 添加顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void AddImageCommand_ExecuteEvent(AnimeModel value)
private void AddBackImageCommand_ExecuteEvent(FoodAnimeModel value)
{
OpenFileDialog openFileDialog =
new() { Title = "选择图片".Translate(), Filter = $"图片|*.png".Translate() };
new()
{
Title = "选择图片".Translate(),
Filter = $"图片|*.png".Translate(),
Multiselect = true
};
if (openFileDialog.ShowDialog() is true)
{
value.Images.Add(new(Utils.LoadImageToMemoryStream(openFileDialog.FileName)));
AddImages(value.BackImages, openFileDialog.FileNames);
}
}
/// <summary>
/// 删除顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void RemoveBackImageCommand_ExecuteEvent(FoodAnimeModel value)
{
value.BackImages.Remove(CurrentBackImageModel.Value);
CurrentBackImageModel.Value.Close();
}
/// <summary>
/// 清空顶层图片
/// </summary>
/// <param name="value">动画模型</param>
private void ClearBackImageCommand_ExecuteEvent(FoodAnimeModel value)
{
if (
MessageBox.Show("确定清空吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
)
{
foreach (var image in value.BackImages)
image.Close();
value.BackImages.Clear();
}
}
#endregion
/// <summary>
/// 添加图片
/// </summary>
/// <param name="model">动画模型</param>
/// <param name="images">动画</param>
/// <param name="paths">路径</param>
public void AddImages(AnimeModel model, IEnumerable<string> paths)
public void AddImages(ObservableCollection<ImageModel> images, IEnumerable<string> paths)
{
try
{
var newImages = new List<ImageModel>();
foreach (string path in paths)
{
if (File.Exists(path))
{
model.Images.Add(new(Utils.LoadImageToMemoryStream(path)));
newImages.Add(new(Utils.LoadImageToMemoryStream(path)));
}
else if (Directory.Exists(path))
{
foreach (var file in Directory.EnumerateFiles(path, "*.png"))
{
model.Images.Add(new(Utils.LoadImageToMemoryStream(path)));
newImages.Add(new(Utils.LoadImageToMemoryStream(path)));
}
}
}
foreach (var image in newImages)
images.Add(image);
}
catch (Exception ex)
{
MessageBox.Show("添加失败 \n{0}".Translate(ex));
}
}
/// <summary>
/// 删除图片
/// </summary>
/// <param name="value">动画模型</param>
private void RemoveImageCommand_ExecuteEvent(AnimeModel value)
#endregion
#region FoodLocationCommand
private void AddeFoodLocationCommand_ExecuteEvent(FoodAnimeModel value)
{
CurrentFrontImageModel.Value.Close();
value.Images.Remove(CurrentFrontImageModel.Value);
value.FoodLocations.Add(new());
}
private void RemoveFoodLocationCommand_ExecuteEvent(FoodAnimeModel value)
{
value.FoodLocations.Remove(CurrentFoodLocationModel.Value);
CurrentFoodLocationModel.Value = null;
}
private void ClearFoodLocationCommand_ExecuteEvent(FoodAnimeModel value)
{
if (
MessageBox.Show("确定清空吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
)
{
value.FoodLocations.Clear();
}
}
#endregion
#region FrontPlayer
private void CurrentAnimeModel_ValueChanged(FoodAnimeModel oldValue, FoodAnimeModel newValue)
{
@ -327,19 +481,13 @@ public class FoodAnimeEditWindowVM
{
if (_playing is false)
return;
Reset();
}
/// <summary>
/// 开始播放
/// </summary>
private void PlayCommand_ExecuteEvent()
private async Task PlayCommand_AsyncExecuteEvent()
{
if (_playing)
{
MessageBox.Show("正在播放".Translate());
return;
}
if (CurrentAnimeModel.Value is null)
{
MessageBox.Show("未选中动画".Translate());
@ -349,6 +497,8 @@ public class FoodAnimeEditWindowVM
_frontPlayerTask.Start();
_backPlayerTask.Start();
_foodPlayerTask.Start();
await Task.WhenAll(_frontPlayerTask, _backPlayerTask, _foodPlayerTask);
Reset();
}
/// <summary>

View File

@ -12,6 +12,7 @@
Width="1000"
Height="600"
d:DataContext="{d:DesignInstance Type=vm:AnimeEditWindowVM}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<Style
@ -30,17 +31,23 @@
<Expander.ContextMenu>
<ContextMenu d:DataContext="">
<MenuItem
d:Header="添加图片"
Command="{Binding PlacementTarget.Tag.AddImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 添加图片}" />
Header="{ll:Str 添加图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="清空图片"
Command="{Binding PlacementTarget.Tag.ClearImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 清空图片}" />
Header="{ll:Str 清空图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="删除此项"
Command="{Binding PlacementTarget.Tag.RemoveAnimeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 删除此项}" />
Header="{ll:Str 删除此项}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
</ContextMenu>
</Expander.ContextMenu>
<Expander.Header>
@ -59,8 +66,9 @@
</TextBlock>
<TextBox
Grid.Column="1"
pu:TextBoxHelper.Watermark="{ll:Str 动画Id}"
pu:TextBoxHelper.Watermark="{ll:Str 动画Id(非必要)}"
Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
<!-- pu:TextBoxHelper.Watermark="{ll:Str 动画Id(非必要)}" -->
<ComboBox
Grid.Column="2"
Margin="10,0,0,0"
@ -89,9 +97,17 @@
<Grid.ContextMenu>
<ContextMenu>
<MenuItem
d:Header="修改图片"
Command="{Binding PlacementTarget.Tag.ChangeImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 修改图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="删除图片"
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 删除图片}" />
Header="{ll:Str 删除图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
</ContextMenu>
</Grid.ContextMenu>
<Grid.RowDefinitions>
@ -116,7 +132,7 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Content="{ll:Str 持续时间(ms)}" />
<Label d:Content="持续时间(ms)" Content="{ll:Str 持续时间(ms)}" />
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
</Grid>
</Grid>
@ -263,7 +279,7 @@
<Button
x:Name="Button_AddAnime"
Margin="10"
Click="Button_AddAnime_Click"
Command="{Binding AddAnimeCommand}"
Content="{ll:Str 添加动画}" />
<Button
x:Name="Button_Cancel"

View File

@ -105,7 +105,7 @@ public partial class AnimeEditWindow : Window
if (sender is not ListBox listBox)
return;
if (e.Data.GetData(DataFormats.FileDrop) is Array array)
ViewModel.AddImages((AnimeModel)listBox.DataContext, array.Cast<string>());
ViewModel.AddImages(((AnimeModel)listBox.DataContext).Images, array.Cast<string>());
if (_dropSender is not null && sender.Equals(_dropSender) is false)
{
MessageBox.Show("无法移动不同动画的图片".Translate());
@ -163,18 +163,6 @@ public partial class AnimeEditWindow : Window
return null;
}
private void Button_AddAnime_Click(object sender, RoutedEventArgs e)
{
if (ViewModel.CurrentMode is GameSave.ModeType.Happy)
ViewModel.Anime.Value.HappyAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.Nomal)
ViewModel.Anime.Value.NomalAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.PoorCondition)
ViewModel.Anime.Value.PoorConditionAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.Ill)
ViewModel.Anime.Value.IllAnimes.Add(new());
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is not ListBox listBox)

View File

@ -32,8 +32,8 @@ public partial class AnimePage : Page
private void DataGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (sender is not DataGrid dataGrid || dataGrid.SelectedItem is not AnimeTypeModel model)
if (sender is not DataGrid dataGrid || dataGrid.SelectedItem is null)
return;
ViewModel.Edit(model);
ViewModel.Edit(dataGrid.SelectedItem);
}
}

View File

@ -12,6 +12,7 @@
Width="1000"
Height="600"
d:DataContext="{d:DesignInstance Type=vm:FoodAnimeEditWindowVM}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<Style
@ -33,17 +34,20 @@
d:Header="添加图片"
Command="{Binding PlacementTarget.Tag.AddImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 添加图片}" />
Header="{ll:Str 添加图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="添加图片"
Command="{Binding PlacementTarget.Tag.ClearImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 清空图片}" />
Header="{ll:Str 清空图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="添加图片"
Command="{Binding PlacementTarget.Tag.RemoveAnimeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 删除此项}" />
Header="{ll:Str 删除此项}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
</ContextMenu>
</Expander.ContextMenu>
<Expander.Header>
@ -53,13 +57,13 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Margin="10,0,10,0">
<!--<TextBlock Margin="10,0,10,0">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})">
<Binding Path="Images.Count" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</TextBlock>-->
<TextBox Grid.Column="1" Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
<!-- pu:TextBoxHelper.Watermark="{ll:Str 动画Id(非必要)}" -->
</Grid>
@ -97,11 +101,18 @@
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem
d:Header="修改图片"
Command="{Binding PlacementTarget.Tag.ChangeImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 修改图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="删除图片"
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 删除图片}" />
Header="{ll:Str 删除图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
</ContextMenu>
</Grid.ContextMenu>
<Grid.RowDefinitions>
@ -157,6 +168,12 @@
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem
d:Header="修改图片"
Command="{Binding PlacementTarget.Tag.ChangeImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 修改图片}"
IsEnabled="{Binding PlacementTarget.Tag.PlayCommand.CurrentCanExecute.Value, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" />
<MenuItem
d:Header="删除图片"
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
@ -307,11 +324,13 @@
Height="250"
Source="{Binding CurrentBackImageModel.Value.Image.Value}" />
<Image
x:Name="Image_Center"
Width="250"
Height="250"
x:Name="Image_Food"
Height="{Binding Width, RelativeSource={RelativeSource Mode=Self}}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Opacity="{Binding CurrentFoodLocationModel.Value.Opacity.Value}"
RenderTransformOrigin="0,0">
RenderTransformOrigin="0,0"
Source="{Binding FoodImage.Value}">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform />
@ -325,15 +344,7 @@
<Setter Property="Width">
<Setter.Value>
<MultiBinding Converter="{StaticResource CalculatorConverter}" ConverterParameter="*">
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Width.Value" />
<Binding Path="LengthRatio.Value" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Height">
<Setter.Value>
<MultiBinding Converter="{StaticResource CalculatorConverter}" ConverterParameter="*">
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Width.Value" />
<Binding Path="CurrentFoodLocationModel.Value.Rect.Width.Value" />
<Binding Path="LengthRatio.Value" />
</MultiBinding>
</Setter.Value>
@ -342,8 +353,8 @@
<Setter.Value>
<MultiBinding Converter="{StaticResource RatioMarginConverter}">
<Binding Path="LengthRatio.Value" />
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.X.Value" />
<Binding Path="CurrentFoodLocationModel.Value.Rect.Value.Y.Value" />
<Binding Path="CurrentFoodLocationModel.Value.Rect.X.Value" />
<Binding Path="CurrentFoodLocationModel.Value.Rect.Y.Value" />
</MultiBinding>
</Setter.Value>
</Setter>
@ -488,7 +499,7 @@
<Button
x:Name="Button_AddAnime"
Margin="10"
Click="Button_AddAnime_Click"
Command="{Binding AddAnimeCommand}"
Content="{ll:Str 添加动画}" />
<Button
x:Name="Button_Cancel"

View File

@ -37,7 +37,7 @@ public partial class FoodAnimeEditWindow : Window
};
}
public AnimeEditWindowVM ViewModel => (AnimeEditWindowVM)DataContext;
public FoodAnimeEditWindowVM ViewModel => (FoodAnimeEditWindowVM)DataContext;
public bool IsCancel { get; private set; } = true;
@ -63,7 +63,9 @@ public partial class FoodAnimeEditWindow : Window
if (Enum.TryParse<GameSave.ModeType>(str, true, out var mode))
{
ViewModel.CurrentMode = mode;
ViewModel.CurrentImageModel.Value = null;
ViewModel.CurrentFrontImageModel.Value = null;
ViewModel.CurrentBackImageModel.Value = null;
ViewModel.CurrentFoodLocationModel.Value = null;
ViewModel.CurrentAnimeModel.Value = null;
}
}
@ -84,54 +86,54 @@ public partial class FoodAnimeEditWindow : Window
private void ListBox_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (sender is not ListBox listBox)
return;
if (e.LeftButton != MouseButtonState.Pressed)
return;
var pos = e.GetPosition(listBox);
HitTestResult result = VisualTreeHelper.HitTest(listBox, pos);
if (result is null)
return;
var listBoxItem = FindVisualParent<ListBoxItem>(result.VisualHit);
if (listBoxItem == null || listBoxItem.Content != listBox.SelectedItem)
return;
var dataObj = new DataObject(listBoxItem.Content);
DragDrop.DoDragDrop(listBox, dataObj, DragDropEffects.Move);
_dropSender = sender;
//if (sender is not ListBox listBox)
// return;
//if (e.LeftButton != MouseButtonState.Pressed)
// return;
//var pos = e.GetPosition(listBox);
//HitTestResult result = VisualTreeHelper.HitTest(listBox, pos);
//if (result is null)
// return;
//var listBoxItem = FindVisualParent<ListBoxItem>(result.VisualHit);
//if (listBoxItem == null || listBoxItem.Content != listBox.SelectedItem)
// return;
//var dataObj = new DataObject(listBoxItem.Content);
//DragDrop.DoDragDrop(listBox, dataObj, DragDropEffects.Move);
//_dropSender = sender;
}
private void ListBox_Drop(object sender, DragEventArgs e)
{
if (sender is not ListBox listBox)
return;
if (e.Data.GetData(DataFormats.FileDrop) is Array array)
ViewModel.AddImages((AnimeModel)listBox.DataContext, array.Cast<string>());
if (_dropSender is not null && sender.Equals(_dropSender) is false)
{
MessageBox.Show("无法移动不同动画的图片".Translate());
return;
}
var pos = e.GetPosition(listBox);
var result = VisualTreeHelper.HitTest(listBox, pos);
if (result == null)
return;
//查找元数据
if (e.Data.GetData(typeof(ImageModel)) is not ImageModel sourcePerson)
return;
//查找目标数据
var listBoxItem = FindVisualParent<ListBoxItem>(result.VisualHit);
if (listBoxItem == null)
return;
var targetPerson = listBoxItem.Content as ImageModel;
if (ReferenceEquals(targetPerson, sourcePerson))
return;
if (listBox.ItemsSource is not IList<ImageModel> list)
return;
var sourceIndex = list.IndexOf(sourcePerson);
var targetIndex = list.IndexOf(targetPerson);
var temp = list[sourceIndex];
list[sourceIndex] = list[targetIndex];
list[targetIndex] = temp;
//if (sender is not ListBox listBox)
// return;
//if (e.Data.GetData(DataFormats.FileDrop) is Array array)
// ViewModel.AddImages(((AnimeModel)listBox.DataContext, array.Cast<string>());
//if (_dropSender is not null && sender.Equals(_dropSender) is false)
//{
// MessageBox.Show("无法移动不同动画的图片".Translate());
// return;
//}
//var pos = e.GetPosition(listBox);
//var result = VisualTreeHelper.HitTest(listBox, pos);
//if (result == null)
// return;
////查找元数据
//if (e.Data.GetData(typeof(ImageModel)) is not ImageModel sourcePerson)
// return;
////查找目标数据
//var listBoxItem = FindVisualParent<ListBoxItem>(result.VisualHit);
//if (listBoxItem == null)
// return;
//var targetPerson = listBoxItem.Content as ImageModel;
//if (ReferenceEquals(targetPerson, sourcePerson))
// return;
//if (listBox.ItemsSource is not IList<ImageModel> list)
// return;
//var sourceIndex = list.IndexOf(sourcePerson);
//var targetIndex = list.IndexOf(targetPerson);
//var temp = list[sourceIndex];
//list[sourceIndex] = list[targetIndex];
//list[targetIndex] = temp;
}
public static T? FindVisualChild<T>(DependencyObject obj)
@ -163,23 +165,11 @@ public partial class FoodAnimeEditWindow : Window
return null;
}
private void Button_AddAnime_Click(object sender, RoutedEventArgs e)
{
if (ViewModel.CurrentMode is GameSave.ModeType.Happy)
ViewModel.Anime.Value.HappyAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.Nomal)
ViewModel.Anime.Value.NomalAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.PoorCondition)
ViewModel.Anime.Value.PoorConditionAnimes.Add(new());
else if (ViewModel.CurrentMode is GameSave.ModeType.Ill)
ViewModel.Anime.Value.IllAnimes.Add(new());
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is not ListBox listBox)
return;
if (listBox.DataContext is AnimeModel model)
if (listBox.DataContext is FoodAnimeModel model)
ViewModel.CurrentAnimeModel.Value = model;
e.Handled = true;
}