This commit is contained in:
Hakoyu 2023-10-15 23:11:04 +08:00
parent 171c49012c
commit c58ddf25fa
11 changed files with 529 additions and 165 deletions

View File

@ -23,19 +23,19 @@ public class FoodAnimeModel
/// <summary> /// <summary>
/// 后图像列表 /// 后图像列表
/// </summary> /// </summary>
public ObservableCollection<ImageModel> BackImages { get; } = new(); public ObservableCollection<ImageModel> BackImages { get; set; } = new();
public ObservableValue<FoodImagesPath> BackImagesPath { get; } = new(); public ObservableValue<FoodImagesPath?> BackImagesPath { get; } = new();
/// <summary> /// <summary>
/// 前图像列表 /// 前图像列表
/// </summary> /// </summary>
public ObservableCollection<ImageModel> FrontImages { get; } = new(); public ObservableCollection<ImageModel> FrontImages { get; set; } = new();
public ObservableValue<FoodImagesPath> FrontImagesPath { get; } = new(); public ObservableValue<FoodImagesPath?> FrontImagesPath { get; } = new();
/// <summary> /// <summary>
/// 食物定位列表 /// 食物定位列表
/// </summary> /// </summary>
public ObservableCollection<FoodLocationInfoModel> FoodLocations { get; } = new(); public ObservableCollection<FoodLocationModel> FoodLocations { get; } = new();
public FoodAnimeModel() { } public FoodAnimeModel() { }
@ -46,7 +46,7 @@ public class FoodAnimeModel
{ {
//var index = int.Parse(item.Name.Substring(1)); //var index = int.Parse(item.Name.Substring(1));
var infos = item.Info.Split(','); var infos = item.Info.Split(',');
var foodLocationInfo = new FoodLocationInfoModel(); var foodLocationInfo = new FoodLocationModel();
foodLocationInfo.Duration.Value = int.Parse(infos[0]); foodLocationInfo.Duration.Value = int.Parse(infos[0]);
if (infos.Length > 1) if (infos.Length > 1)
{ {

View File

@ -4,6 +4,7 @@ using LinePutScript.Localization.WPF;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -24,6 +25,11 @@ public class FoodAnimeTypeModel
/// </summary> /// </summary>
public ObservableValue<string> Name { get; } = new(); public ObservableValue<string> Name { get; } = new();
/// <summary>
/// 动作类型
/// </summary>
public GraphInfo.GraphType GraphType => GraphInfo.GraphType.Common;
/// <summary> /// <summary>
/// 开心动画 /// 开心动画
/// </summary> /// </summary>
@ -46,28 +52,73 @@ public class FoodAnimeTypeModel
public FoodAnimeTypeModel() public FoodAnimeTypeModel()
{ {
HappyAnimes.CollectionChanged += Animes_CollectionChanged;
//Name.ValueChanged += (_, _) => //Name.ValueChanged += (_, _) =>
//{ //{
// Id.Value = $"{GraphType.Value}_{Name.Value}"; // Id.Value = $"{GraphType.Value}_{Name.Value}";
//}; //};
} }
private void Animes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems is not null)
{
foreach (var model in e.NewItems.Cast<FoodAnimeModel>())
{
SetImagesPathValueChanged(model);
}
}
if (e.OldItems is not null)
{
foreach (var model in e.OldItems.Cast<FoodAnimeModel>())
{
SetImagesPathValueChanged(model);
}
}
}
private void SetImagesPathValueChanged(FoodAnimeModel model)
{
model.FrontImagesPath.ValueChanged += (o, n) =>
{
if (n is null)
return;
if (n.Mode.Value is GameSave.ModeType.Happy)
model.FrontImages = HappyAnimes[n.Index.Value].FrontImages;
else if (n.Mode.Value is GameSave.ModeType.Nomal)
model.FrontImages = NomalAnimes[n.Index.Value].FrontImages;
else if (n.Mode.Value is GameSave.ModeType.PoorCondition)
model.FrontImages = PoorConditionAnimes[n.Index.Value].FrontImages;
else if (n.Mode.Value is GameSave.ModeType.Ill)
model.FrontImages = IllAnimes[n.Index.Value].FrontImages;
};
model.BackImagesPath.ValueChanged += (o, n) =>
{
if (n is null)
return;
if (n.Mode.Value is GameSave.ModeType.Happy)
model.BackImages = HappyAnimes[n.Index.Value].BackImages;
else if (n.Mode.Value is GameSave.ModeType.Nomal)
model.BackImages = NomalAnimes[n.Index.Value].BackImages;
else if (n.Mode.Value is GameSave.ModeType.PoorCondition)
model.BackImages = PoorConditionAnimes[n.Index.Value].BackImages;
else if (n.Mode.Value is GameSave.ModeType.Ill)
model.BackImages = IllAnimes[n.Index.Value].BackImages;
};
}
public FoodAnimeTypeModel(string path) public FoodAnimeTypeModel(string path)
: this() : this()
{ {
Name.Value = Path.GetFileName(path); Name.Value = Path.GetFileName(path);
var infoFile = Path.Combine(path, ModMakerInfo.InfoFile); var infoFile = Path.Combine(path, ModMakerInfo.InfoFile);
if (File.Exists(infoFile) is false) if (
Directory.EnumerateFiles(path, ModMakerInfo.InfoFile, SearchOption.AllDirectories).Any()
is false
)
throw new Exception("信息文件\n{0}\n不存在".Translate(infoFile)); throw new Exception("信息文件\n{0}\n不存在".Translate(infoFile));
var lps = new LPS(infoFile); if (File.Exists(infoFile))
var foodAnime = lps.FindAllLineInfo(nameof(FoodAnimation)); ParseInfoFile(path, infoFile);
if (foodAnime.Any() is false)
throw new Exception("信息文件\n{0}\n未包含食物动画信息".Translate(infoFile));
var anime = lps.FindAllLineInfo(nameof(PNGAnimation));
foreach (var foodAnimation in foodAnime)
{
ParseFoodAnimeInfo(foodAnimation);
}
} }
public FoodAnimeTypeModel(FoodAnimeTypeModel model) public FoodAnimeTypeModel(FoodAnimeTypeModel model)
@ -104,21 +155,115 @@ public class FoodAnimeTypeModel
} }
} }
public void ParseFoodAnimeInfo(ILine line) public void ParseInfoFile(string path, string infoPath)
{ {
var mode = (GameSave.ModeType)Enum.Parse(typeof(GameSave.ModeType), line.Find("mode").Info); var lps = new LPS(infoPath);
if (mode is GameSave.ModeType.Happy) var foodAnimeInfos = lps.FindAllLineInfo(nameof(FoodAnimation));
AddModeAnime(HappyAnimes, line); if (foodAnimeInfos.Any() is false)
else if (mode is GameSave.ModeType.Nomal) throw new Exception("信息文件\n{0}\n未包含食物动画信息".Translate(infoPath));
AddModeAnime(NomalAnimes, line); var pngAnimeInfos = lps.FindAllLineInfo(nameof(PNGAnimation))
else if (mode is GameSave.ModeType.PoorCondition) .Select(
AddModeAnime(PoorConditionAnimes, line); i =>
else if (mode is GameSave.ModeType.Ill) new PNGAnimeInfo(
AddModeAnime(IllAnimes, line); i.Info,
i.Find("infoPath").Info,
(GameSave.ModeType)
Enum.Parse(typeof(GameSave.ModeType), i.Find("mode").Info, true)
)
)
.ToList();
foreach (var foodAnimation in foodAnimeInfos)
{
ParseFoodAnimeInfo(path, foodAnimation, pngAnimeInfos);
}
} }
public void AddModeAnime(ObservableCollection<FoodAnimeModel> foodAnimes, ILine line) public void ParseFoodAnimeInfo(string path, ILine line, List<PNGAnimeInfo> pngAnimeInfos)
{ {
foodAnimes.Add(new(line)); var mode = (GameSave.ModeType)
Enum.Parse(typeof(GameSave.ModeType), line.Find("mode").Info, true);
if (mode is GameSave.ModeType.Happy)
AddModeAnime(path, GameSave.ModeType.Happy, HappyAnimes, line, pngAnimeInfos);
else if (mode is GameSave.ModeType.Nomal)
AddModeAnime(path, GameSave.ModeType.Nomal, NomalAnimes, line, pngAnimeInfos);
else if (mode is GameSave.ModeType.PoorCondition)
AddModeAnime(
path,
GameSave.ModeType.PoorCondition,
PoorConditionAnimes,
line,
pngAnimeInfos
);
else if (mode is GameSave.ModeType.Ill)
AddModeAnime(path, GameSave.ModeType.Ill, IllAnimes, line, pngAnimeInfos);
}
public void AddModeAnime(
string path,
GameSave.ModeType mode,
ObservableCollection<FoodAnimeModel> foodAnimes,
ILine line,
List<PNGAnimeInfo> pngAnimeInfos
)
{
var anime = new FoodAnimeModel(line);
var frontLay = line.Find("front_lay").Info;
var backLay = line.Find("back_lay").Info;
var frontLayAnimes = pngAnimeInfos.Where(i => i.Name == frontLay).ToList();
var backLayAnimes = pngAnimeInfos.Where(i => i.Name == backLay).ToList();
// 尝试获取相同模式的动画
if (frontLayAnimes.FirstOrDefault(i => i.Mode == mode) is PNGAnimeInfo frontAnimeInfo)
{
anime.FrontImages = GetImages(path, frontAnimeInfo);
}
else
{
// 若没有则获取通用动画
anime.FrontImages = GetImages(
path,
frontLayAnimes.First(i => i.Mode == GameSave.ModeType.Nomal)
);
}
if (backLayAnimes.FirstOrDefault(i => i.Mode == mode) is PNGAnimeInfo backAnimeInfo)
{
anime.BackImages = GetImages(path, backAnimeInfo);
}
else
{
anime.BackImages = GetImages(
path,
backLayAnimes.First(i => i.Mode == GameSave.ModeType.Nomal)
);
}
foodAnimes.Add(anime);
static ObservableCollection<ImageModel> GetImages(string path, PNGAnimeInfo pngAnimeInfo)
{
return new(
Directory
.EnumerateFiles(Path.Combine(path, pngAnimeInfo.Path))
.Select(
i =>
new ImageModel(
Utils.LoadImageToMemoryStream(i),
int.Parse(Path.GetFileNameWithoutExtension(i).Split('_')[1])
)
)
);
}
}
}
public class PNGAnimeInfo
{
public string Name { get; }
public string Path { get; }
public GameSave.ModeType Mode { get; }
public PNGAnimeInfo(string name, string path, GameSave.ModeType mode)
{
Name = name;
Path = path;
Mode = mode;
} }
} }

View File

@ -10,7 +10,7 @@ namespace VPet.ModMaker.Models.ModModel;
/// <summary> /// <summary>
/// 食物图像模型 /// 食物图像模型
/// </summary> /// </summary>
public class FoodLocationInfoModel public class FoodLocationModel
{ {
/// <summary> /// <summary>
/// 持续时间 /// 持续时间
@ -32,7 +32,7 @@ public class FoodLocationInfoModel
/// </summary> /// </summary>
public ObservableValue<double> Opacity { get; } = new(100); public ObservableValue<double> Opacity { get; } = new(100);
public FoodLocationInfoModel() public FoodLocationModel()
{ {
Rect.Width.ValueChanged += (o, n) => Rect.Width.ValueChanged += (o, n) =>
{ {
@ -40,9 +40,9 @@ public class FoodLocationInfoModel
}; };
} }
public FoodLocationInfoModel Copy() public FoodLocationModel Copy()
{ {
var model = new FoodLocationInfoModel(); var model = new FoodLocationModel();
model.Duration.Value = Duration.Value; model.Duration.Value = Duration.Value;
model.Rect.SetValue(Rect.X.Value, Rect.Y.Value, Rect.Width.Value, Rect.Height.Value); model.Rect.SetValue(Rect.X.Value, Rect.Y.Value, Rect.Width.Value, Rect.Height.Value);
model.Rotate.Value = Rotate.Value; model.Rotate.Value = Rotate.Value;

View File

@ -70,6 +70,11 @@ public class PetModel : I18nModel<I18nPetInfoModel>
/// </summary> /// </summary>
public ObservableCollection<AnimeTypeModel> Animes { get; } = new(); public ObservableCollection<AnimeTypeModel> Animes { get; } = new();
/// <summary>
///食物动画
/// </summary>
public ObservableCollection<FoodAnimeTypeModel> FoodAnimes { get; } = new();
public bool IsSimplePetModel { get; } = false; public bool IsSimplePetModel { get; } = false;
public PetModel() public PetModel()

View File

@ -34,6 +34,11 @@ public class ObservableValue<T> : INotifyPropertyChanging, INotifyPropertyChange
} }
} }
/// <summary>
/// 含有值
/// </summary>
public bool HasValue => Value != null;
#region Ctor #region Ctor
/// <inheritdoc/> /// <inheritdoc/>
public ObservableValue() { } public ObservableValue() { }

View File

@ -106,7 +106,7 @@
<Compile Include="Models\Expansions.cs" /> <Compile Include="Models\Expansions.cs" />
<Compile Include="Models\ModModel\FoodAnimeModel.cs" /> <Compile Include="Models\ModModel\FoodAnimeModel.cs" />
<Compile Include="Models\ModModel\FoodAnimeTypeModel.cs" /> <Compile Include="Models\ModModel\FoodAnimeTypeModel.cs" />
<Compile Include="Models\ModModel\FoodLocationInfoModel.cs" /> <Compile Include="Models\ModModel\FoodLocationModel.cs" />
<Compile Include="Models\ModModel\FoodModel.cs" /> <Compile Include="Models\ModModel\FoodModel.cs" />
<Compile Include="Models\I18nHelper.cs" /> <Compile Include="Models\I18nHelper.cs" />
<Compile Include="Models\I18nModel.cs" /> <Compile Include="Models\I18nModel.cs" />

View File

@ -286,7 +286,6 @@ public class AnimeEditWindowVM
return; return;
} }
} while (Loop.Value); } while (Loop.Value);
Reset();
} }
/// <summary> /// <summary>

View File

@ -7,8 +7,10 @@ using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Media.Imaging;
using VPet.ModMaker.Models; using VPet.ModMaker.Models;
using VPet.ModMaker.Models.ModModel; using VPet.ModMaker.Models.ModModel;
using VPet_Simulator.Core; using VPet_Simulator.Core;
@ -22,25 +24,45 @@ public class FoodAnimeEditWindowVM
/// </summary> /// </summary>
public PetModel CurrentPet { get; set; } public PetModel CurrentPet { get; set; }
/// <summary>
/// 食物图片
/// </summary>
public ObservableValue<BitmapImage> FoodImage { get; } = new();
/// <summary>
/// 比例
/// </summary>
public ObservableValue<double> LengthRatio { get; } = new(250.0 / 500.0);
/// <summary> /// <summary>
/// 旧动画 /// 旧动画
/// </summary> /// </summary>
public AnimeTypeModel OldAnime { get; set; } public FoodAnimeTypeModel OldAnime { get; set; }
/// <summary> /// <summary>
/// 动画 /// 动画
/// </summary> /// </summary>
public ObservableValue<AnimeTypeModel> Anime { get; } = new(new()); public ObservableValue<FoodAnimeTypeModel> Anime { get; } = new(new());
/// <summary> /// <summary>
/// 当前图像模型 /// 当前顶层图像模型
/// </summary> /// </summary>
public ObservableValue<ImageModel> CurrentImageModel { get; } = new(); public ObservableValue<ImageModel> CurrentFrontImageModel { get; } = new();
/// <summary>
/// 当前底层图像模型
/// </summary>
public ObservableValue<ImageModel> CurrentBackImageModel { get; } = new();
/// <summary>
/// 当前食物定位模型
/// </summary>
public ObservableValue<FoodLocationModel> CurrentFoodLocationModel { get; } = new();
/// <summary> /// <summary>
/// 当前动画模型 /// 当前动画模型
/// </summary> /// </summary>
public ObservableValue<AnimeModel> CurrentAnimeModel { get; } = new(); public ObservableValue<FoodAnimeModel> CurrentAnimeModel { get; } = new();
/// <summary> /// <summary>
/// 当前模式 /// 当前模式
@ -100,13 +122,25 @@ public class FoodAnimeEditWindowVM
private bool _playing = false; private bool _playing = false;
/// <summary> /// <summary>
/// 动画任务 /// 顶层动画任务
/// </summary> /// </summary>
private Task _playerTask; private Task _frontPlayerTask;
/// <summary>
/// 底层动画任务
/// </summary>
private Task _backPlayerTask;
/// <summary>
/// 食物动画任务
/// </summary>
private Task _foodPlayerTask;
public FoodAnimeEditWindowVM() public FoodAnimeEditWindowVM()
{ {
_playerTask = new(Play); _frontPlayerTask = new(FrontPlay);
_backPlayerTask = new(BackPlay);
_foodPlayerTask = new(FoodPlay);
CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged; CurrentAnimeModel.ValueChanged += CurrentAnimeModel_ValueChanged;
@ -121,18 +155,18 @@ public class FoodAnimeEditWindowVM
} }
#region LoadAnime #region LoadAnime
private void Anime_ValueChanged(AnimeTypeModel oldValue, AnimeTypeModel newValue) private void Anime_ValueChanged(FoodAnimeTypeModel oldValue, FoodAnimeTypeModel newValue)
{ {
CheckGraphType(newValue); CheckGraphType(newValue);
} }
private void CheckGraphType(AnimeTypeModel model) private void CheckGraphType(FoodAnimeTypeModel model)
{ {
if (AnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value)) //if (FoodAnimeTypeModel.HasMultiTypeAnimes.Contains(model.GraphType.Value))
HasMultiType.Value = true; // HasMultiType.Value = true;
if (AnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value)) //if (FoodAnimeTypeModel.HasNameAnimes.Contains(model.GraphType.Value))
HasAnimeName.Value = true; // HasAnimeName.Value = true;
} }
#endregion #endregion
/// <summary> /// <summary>
@ -146,14 +180,14 @@ public class FoodAnimeEditWindowVM
MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes MessageBox.Show("确定删除吗".Translate(), "", MessageBoxButton.YesNo) is MessageBoxResult.Yes
) )
{ {
if (CurrentMode is GameSave.ModeType.Happy) //if (CurrentMode is GameSave.ModeType.Happy)
Anime.Value.HappyAnimes.Remove(value); // Anime.Value.HappyAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.Nomal) //else if (CurrentMode is GameSave.ModeType.Nomal)
Anime.Value.NomalAnimes.Remove(value); // Anime.Value.NomalAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.PoorCondition) //else if (CurrentMode is GameSave.ModeType.PoorCondition)
Anime.Value.PoorConditionAnimes.Remove(value); // Anime.Value.PoorConditionAnimes.Remove(value);
else if (CurrentMode is GameSave.ModeType.Ill) //else if (CurrentMode is GameSave.ModeType.Ill)
Anime.Value.IllAnimes.Remove(value); // Anime.Value.IllAnimes.Remove(value);
value.Close(); value.Close();
} }
} }
@ -223,18 +257,26 @@ public class FoodAnimeEditWindowVM
/// <param name="value">动画模型</param> /// <param name="value">动画模型</param>
private void RemoveImageCommand_ExecuteEvent(AnimeModel value) private void RemoveImageCommand_ExecuteEvent(AnimeModel value)
{ {
CurrentImageModel.Value.Close(); CurrentFrontImageModel.Value.Close();
value.Images.Remove(CurrentImageModel.Value); value.Images.Remove(CurrentFrontImageModel.Value);
} }
#region Player #region FrontPlayer
private void CurrentAnimeModel_ValueChanged(AnimeModel oldValue, AnimeModel newValue) private void CurrentAnimeModel_ValueChanged(FoodAnimeModel oldValue, FoodAnimeModel newValue)
{ {
StopCommand_ExecuteEvent(); StopCommand_ExecuteEvent();
if (oldValue is not null) if (oldValue is not null)
oldValue.Images.CollectionChanged -= Images_CollectionChanged; {
oldValue.FrontImages.CollectionChanged -= Images_CollectionChanged;
oldValue.BackImages.CollectionChanged -= Images_CollectionChanged;
oldValue.FoodLocations.CollectionChanged -= Images_CollectionChanged;
}
if (newValue is not null) if (newValue is not null)
newValue.Images.CollectionChanged += Images_CollectionChanged; {
newValue.FrontImages.CollectionChanged += Images_CollectionChanged;
newValue.BackImages.CollectionChanged += Images_CollectionChanged;
newValue.FoodLocations.CollectionChanged += Images_CollectionChanged;
}
} }
private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void Images_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@ -268,25 +310,60 @@ public class FoodAnimeEditWindowVM
return; return;
} }
_playing = true; _playing = true;
_playerTask.Start(); _frontPlayerTask.Start();
_backPlayerTask.Start();
_foodPlayerTask.Start();
} }
/// <summary> /// <summary>
/// 播放 /// 顶层播放
/// </summary> /// </summary>
private void Play() private void FrontPlay()
{ {
do do
{ {
foreach (var model in CurrentAnimeModel.Value.Images) foreach (var model in CurrentAnimeModel.Value.FrontImages)
{ {
CurrentImageModel.Value = model; CurrentFrontImageModel.Value = model;
Task.Delay(model.Duration.Value).Wait();
if (_playing is false)
return;
}
} while (Loop.Value);
}
/// <summary>
/// 底层
/// </summary>
private void BackPlay()
{
do
{
foreach (var model in CurrentAnimeModel.Value.BackImages)
{
CurrentBackImageModel.Value = model;
Task.Delay(model.Duration.Value).Wait();
if (_playing is false)
return;
}
} while (Loop.Value);
}
/// <summary>
/// 食物
/// </summary>
private void FoodPlay()
{
do
{
foreach (var model in CurrentAnimeModel.Value.FoodLocations)
{
CurrentFoodLocationModel.Value = model;
Task.Delay(model.Duration.Value).Wait(); Task.Delay(model.Duration.Value).Wait();
if (_playing is false) if (_playing is false)
return; return;
} }
} while (Loop.Value); } while (Loop.Value);
Reset();
} }
/// <summary> /// <summary>
@ -295,7 +372,9 @@ public class FoodAnimeEditWindowVM
private void Reset() private void Reset()
{ {
_playing = false; _playing = false;
_playerTask = new(Play); _frontPlayerTask = new(FrontPlay);
_backPlayerTask = new(BackPlay);
_foodPlayerTask = new(FoodPlay);
} }
#endregion #endregion
} }

View File

@ -46,18 +46,21 @@
<Expander.Header> <Expander.Header>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" MinWidth="200" /> <ColumnDefinition Width="Auto" MinWidth="200" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox pu:TextBoxHelper.Watermark="{ll:Str 动画Id}" Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Margin="10,0,10,0">
<TextBlock Grid.Column="1" Margin="10,0,0,0">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})"> <MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})">
<Binding Path="Images.Count" /> <Binding Path="Images.Count" />
</MultiBinding> </MultiBinding>
</TextBlock.Text> </TextBlock.Text>
</TextBlock> </TextBlock>
<TextBox
Grid.Column="1"
pu:TextBoxHelper.Watermark="{ll:Str 动画Id}"
Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox <ComboBox
Grid.Column="2" Grid.Column="2"
Margin="10,0,0,0" Margin="10,0,0,0"

View File

@ -32,15 +32,15 @@
<MenuItem <MenuItem
Command="{Binding PlacementTarget.Tag.AddImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" Command="{Binding PlacementTarget.Tag.AddImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="添加图片" /> Header="{ll:Str 添加图片}" />
<MenuItem <MenuItem
Command="{Binding PlacementTarget.Tag.ClearImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" Command="{Binding PlacementTarget.Tag.ClearImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="清空图片" /> Header="{ll:Str 清空图片}" />
<MenuItem <MenuItem
Command="{Binding PlacementTarget.Tag.RemoveAnimeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" Command="{Binding PlacementTarget.Tag.RemoveAnimeCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="删除此项" /> Header="{ll:Str 删除此项}" />
</ContextMenu> </ContextMenu>
</Expander.ContextMenu> </Expander.ContextMenu>
<Expander.Header> <Expander.Header>
@ -50,14 +50,17 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox pu:TextBoxHelper.Watermark="动画Id" Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" /> <TextBlock Margin="10,0,10,0">
<TextBlock Grid.Column="1" Margin="10,0,0,0">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})"> <MultiBinding Converter="{StaticResource StringFormatConverter}" ConverterParameter="{}({0})">
<Binding Path="Images.Count" /> <Binding Path="Images.Count" />
</MultiBinding> </MultiBinding>
</TextBlock.Text> </TextBlock.Text>
</TextBlock> </TextBlock>
<TextBox
Grid.Column="1"
pu:TextBoxHelper.Watermark="{ll:Str 动画Id}"
Text="{Binding Id.Value, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox <ComboBox
Grid.Column="2" Grid.Column="2"
Margin="10,0,0,0" Margin="10,0,0,0"
@ -66,6 +69,20 @@
Visibility="{Binding DataContext.HasMultiType.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Converter={StaticResource FalseToHiddenConverter}}" /> Visibility="{Binding DataContext.HasMultiType.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Converter={StaticResource FalseToHiddenConverter}}" />
</Grid> </Grid>
</Expander.Header> </Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" MinWidth="200" />
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox>
<GroupBox.Header>
<Label Content="{ll:Str 顶层图片}" />
</GroupBox.Header>
<ListBox <ListBox
d:ItemsSource="{d:SampleData ItemCount=5}" d:ItemsSource="{d:SampleData ItemCount=5}"
AllowDrop="True" AllowDrop="True"
@ -88,7 +105,7 @@
<MenuItem <MenuItem
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}" CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="删除图片" /> Header="{ll:Str 删除图片}" />
</ContextMenu> </ContextMenu>
</Grid.ContextMenu> </Grid.ContextMenu>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -113,13 +130,78 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="持续时间(ms)" /> <Label Content="{ll:Str 持续时间(ms)}" />
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" /> <pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
</Grid> </Grid>
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
</GroupBox>
<GroupBox Grid.Row="1">
<GroupBox.Header>
<Label Content="{ll:Str 底层图片}" />
</GroupBox.Header>
<ListBox
d:ItemsSource="{d:SampleData ItemCount=5}"
AllowDrop="True"
Drop="ListBox_Drop"
ItemsSource="{Binding Images, IsAsync=True}"
PreviewMouseMove="ListBox_PreviewMouseMove"
PreviewMouseWheel="ListBox_PreviewMouseWheel"
SelectedItem="{Binding DataContext.CurrentImageModel.Value, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Expander, Mode=FindAncestor}}" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem
Command="{Binding PlacementTarget.Tag.RemoveImageCommand, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
CommandParameter="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}"
Header="{ll:Str 删除图片}" />
</ContextMenu>
</Grid.ContextMenu>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Image
Width="150"
Height="150"
d:DataContext=""
DataContext="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
Source="{Binding Image.Value, IsAsync=True}">
<Image.ToolTip>
<Image
Width="250"
Height="250"
Source="{Binding Image.Value, IsAsync=True}" />
</Image.ToolTip>
</Image>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Content="{ll:Str 持续时间(ms)}" />
<pu:NumberInput Grid.Column="1" Value="{Binding DataContext.Duration.Value, RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}" />
</Grid>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
</Grid>
<GroupBox Grid.Column="1">
<ListBox />
</GroupBox>
</Grid>
</Expander> </Expander>
</DataTemplate> </DataTemplate>
</Window.Resources> </Window.Resources>
@ -134,21 +216,67 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="{ll:Str 替换测试食物图片}" />
<MenuItem Header="{ll:Str 重置测试食物图片}" />
</ContextMenu>
</Grid.ContextMenu>
<Image <Image
x:Name="Image_Back" x:Name="Image_Back"
Width="250" Width="250"
Height="250" Height="250"
Source="{Binding CurrentImageModel.Value.Image.Value}" /> Source="{Binding CurrentBackImageModel.Value.Image.Value}" />
<Image <Image
x:Name="Image_Center" x:Name="Image_Center"
Width="250" Width="250"
Height="250" Height="250"
Source="{Binding CurrentImageModel.Value.Image.Value}" /> Opacity="{Binding CurrentFoodLocationModel.Value.Opacity.Value}"
RenderTransformOrigin="0,0">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform Angle="{Binding CurrentFoodLocationModel.Value.Rotate.Value}" />
<TranslateTransform />
</TransformGroup>
</Image.RenderTransform>
<Image.Style>
<Style TargetType="Image">
<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="LengthRatio.Value" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Margin">
<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" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</Image.Style>
</Image>
<Image <Image
x:Name="Image_Front" x:Name="Image_Front"
Width="250" Width="250"
Height="250" Height="250"
Source="{Binding CurrentImageModel.Value.Image.Value}"> Source="{Binding CurrentFrontImageModel.Value.Image.Value}">
<Image.ToolTip> <Image.ToolTip>
<Grid> <Grid>
<Image <Image
@ -166,6 +294,7 @@
</Grid> </Grid>
</Image.ToolTip> </Image.ToolTip>
</Image> </Image>
</Grid>
<Grid Grid.Row="1"> <Grid Grid.Row="1">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition /> <ColumnDefinition />
@ -194,7 +323,7 @@
<!--<Label Content="{ll:Str 动画Id}" /> <!--<Label Content="{ll:Str 动画Id}" />
<TextBox Grid.Column="1" />--> <TextBox Grid.Column="1" />-->
<Label Content="{ll:Str 动画类型}" /> <Label Content="{ll:Str 动画类型}" />
<TextBlock Grid.Column="1" Text="{Binding Anime.Value.GraphType.Value}" /> <TextBlock Grid.Column="1" Text="{Binding Anime.Value.GraphType}" />
<Label <Label
Grid.Row="1" Grid.Row="1"
Content="{ll:Str 动画名称}" Content="{ll:Str 动画名称}"

View File

@ -38,7 +38,6 @@
Text="{Binding LowText.Value.Id.Value, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding LowText.Value.Id.Value, UpdateSourceTrigger=PropertyChanged}" />
</Grid> </Grid>
<TextBox <TextBox
x:Name="TextBox_Text"
Grid.Row="1" Grid.Row="1"
d:Text="这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本," d:Text="这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,这是一个测试文本,"
pu:TextBoxHelper.Watermark="{ll:Str 文本}" pu:TextBoxHelper.Watermark="{ll:Str 文本}"