修改皮肤设置方式为GetSkinStatus/SetSkinStatus

This commit is contained in:
ww-rm
2025-04-18 21:56:50 +08:00
parent 5f026b000c
commit 706c9125e6
4 changed files with 42 additions and 190 deletions

View File

@@ -39,8 +39,7 @@
tabPage_Skin = new TabPage(); tabPage_Skin = new TabPage();
propertyGrid_Skin = new PropertyGrid(); propertyGrid_Skin = new PropertyGrid();
contextMenuStrip_Skin = new ContextMenuStrip(components); contextMenuStrip_Skin = new ContextMenuStrip(components);
toolStripMenuItem_AddSkin = new ToolStripMenuItem(); toolStripMenuItem_ReloadSkins = new ToolStripMenuItem();
toolStripMenuItem_RemoveSkin = new ToolStripMenuItem();
tabPage_Animation = new TabPage(); tabPage_Animation = new TabPage();
propertyGrid_Animation = new PropertyGrid(); propertyGrid_Animation = new PropertyGrid();
contextMenuStrip_Animation = new ContextMenuStrip(components); contextMenuStrip_Animation = new ContextMenuStrip(components);
@@ -108,7 +107,7 @@
tabPage_Render.Location = new Point(4, 4); tabPage_Render.Location = new Point(4, 4);
tabPage_Render.Margin = new Padding(0); tabPage_Render.Margin = new Padding(0);
tabPage_Render.Name = "tabPage_Render"; tabPage_Render.Name = "tabPage_Render";
tabPage_Render.Size = new Size(364, 380); tabPage_Render.Size = new Size(364, 370);
tabPage_Render.TabIndex = 1; tabPage_Render.TabIndex = 1;
tabPage_Render.Text = "渲染"; tabPage_Render.Text = "渲染";
// //
@@ -119,7 +118,7 @@
propertyGrid_Render.Location = new Point(0, 0); propertyGrid_Render.Location = new Point(0, 0);
propertyGrid_Render.Name = "propertyGrid_Render"; propertyGrid_Render.Name = "propertyGrid_Render";
propertyGrid_Render.PropertySort = PropertySort.Alphabetical; propertyGrid_Render.PropertySort = PropertySort.Alphabetical;
propertyGrid_Render.Size = new Size(364, 380); propertyGrid_Render.Size = new Size(364, 370);
propertyGrid_Render.TabIndex = 1; propertyGrid_Render.TabIndex = 1;
propertyGrid_Render.ToolbarVisible = false; propertyGrid_Render.ToolbarVisible = false;
// //
@@ -130,7 +129,7 @@
tabPage_Transform.Location = new Point(4, 4); tabPage_Transform.Location = new Point(4, 4);
tabPage_Transform.Margin = new Padding(0); tabPage_Transform.Margin = new Padding(0);
tabPage_Transform.Name = "tabPage_Transform"; tabPage_Transform.Name = "tabPage_Transform";
tabPage_Transform.Size = new Size(364, 380); tabPage_Transform.Size = new Size(364, 370);
tabPage_Transform.TabIndex = 2; tabPage_Transform.TabIndex = 2;
tabPage_Transform.Text = "变换"; tabPage_Transform.Text = "变换";
// //
@@ -141,7 +140,7 @@
propertyGrid_Transform.Location = new Point(0, 0); propertyGrid_Transform.Location = new Point(0, 0);
propertyGrid_Transform.Name = "propertyGrid_Transform"; propertyGrid_Transform.Name = "propertyGrid_Transform";
propertyGrid_Transform.PropertySort = PropertySort.Alphabetical; propertyGrid_Transform.PropertySort = PropertySort.Alphabetical;
propertyGrid_Transform.Size = new Size(364, 380); propertyGrid_Transform.Size = new Size(364, 370);
propertyGrid_Transform.TabIndex = 1; propertyGrid_Transform.TabIndex = 1;
propertyGrid_Transform.ToolbarVisible = false; propertyGrid_Transform.ToolbarVisible = false;
// //
@@ -152,7 +151,7 @@
tabPage_Skin.Location = new Point(4, 4); tabPage_Skin.Location = new Point(4, 4);
tabPage_Skin.Margin = new Padding(0); tabPage_Skin.Margin = new Padding(0);
tabPage_Skin.Name = "tabPage_Skin"; tabPage_Skin.Name = "tabPage_Skin";
tabPage_Skin.Size = new Size(364, 380); tabPage_Skin.Size = new Size(364, 370);
tabPage_Skin.TabIndex = 3; tabPage_Skin.TabIndex = 3;
tabPage_Skin.Text = "皮肤"; tabPage_Skin.Text = "皮肤";
// //
@@ -164,31 +163,23 @@
propertyGrid_Skin.Location = new Point(0, 0); propertyGrid_Skin.Location = new Point(0, 0);
propertyGrid_Skin.Name = "propertyGrid_Skin"; propertyGrid_Skin.Name = "propertyGrid_Skin";
propertyGrid_Skin.PropertySort = PropertySort.NoSort; propertyGrid_Skin.PropertySort = PropertySort.NoSort;
propertyGrid_Skin.Size = new Size(364, 380); propertyGrid_Skin.Size = new Size(364, 370);
propertyGrid_Skin.TabIndex = 1; propertyGrid_Skin.TabIndex = 1;
propertyGrid_Skin.ToolbarVisible = false; propertyGrid_Skin.ToolbarVisible = false;
// //
// contextMenuStrip_Skin // contextMenuStrip_Skin
// //
contextMenuStrip_Skin.ImageScalingSize = new Size(24, 24); contextMenuStrip_Skin.ImageScalingSize = new Size(24, 24);
contextMenuStrip_Skin.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_AddSkin, toolStripMenuItem_RemoveSkin }); contextMenuStrip_Skin.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_ReloadSkins });
contextMenuStrip_Skin.Name = "contextMenuStrip1"; contextMenuStrip_Skin.Name = "contextMenuStrip1";
contextMenuStrip_Skin.Size = new Size(117, 64); contextMenuStrip_Skin.Size = new Size(225, 34);
contextMenuStrip_Skin.Opening += contextMenuStrip_Skin_Opening;
// //
// toolStripMenuItem_AddSkin // toolStripMenuItem_ReloadSkins
// //
toolStripMenuItem_AddSkin.Name = "toolStripMenuItem_AddSkin"; toolStripMenuItem_ReloadSkins.Name = "toolStripMenuItem_ReloadSkins";
toolStripMenuItem_AddSkin.Size = new Size(116, 30); toolStripMenuItem_ReloadSkins.Size = new Size(224, 30);
toolStripMenuItem_AddSkin.Text = "添加"; toolStripMenuItem_ReloadSkins.Text = "重新加载所选皮肤";
toolStripMenuItem_AddSkin.Click += toolStripMenuItem_AddSkin_Click; toolStripMenuItem_ReloadSkins.Click += toolStripMenuItem_ReloadSkins_Click;
//
// toolStripMenuItem_RemoveSkin
//
toolStripMenuItem_RemoveSkin.Name = "toolStripMenuItem_RemoveSkin";
toolStripMenuItem_RemoveSkin.Size = new Size(116, 30);
toolStripMenuItem_RemoveSkin.Text = "移除";
toolStripMenuItem_RemoveSkin.Click += toolStripMenuItem_RemoveSkin_Click;
// //
// tabPage_Animation // tabPage_Animation
// //
@@ -197,7 +188,7 @@
tabPage_Animation.Location = new Point(4, 4); tabPage_Animation.Location = new Point(4, 4);
tabPage_Animation.Margin = new Padding(0); tabPage_Animation.Margin = new Padding(0);
tabPage_Animation.Name = "tabPage_Animation"; tabPage_Animation.Name = "tabPage_Animation";
tabPage_Animation.Size = new Size(364, 380); tabPage_Animation.Size = new Size(364, 370);
tabPage_Animation.TabIndex = 4; tabPage_Animation.TabIndex = 4;
tabPage_Animation.Text = "动画"; tabPage_Animation.Text = "动画";
// //
@@ -209,7 +200,7 @@
propertyGrid_Animation.Location = new Point(0, 0); propertyGrid_Animation.Location = new Point(0, 0);
propertyGrid_Animation.Name = "propertyGrid_Animation"; propertyGrid_Animation.Name = "propertyGrid_Animation";
propertyGrid_Animation.PropertySort = PropertySort.NoSort; propertyGrid_Animation.PropertySort = PropertySort.NoSort;
propertyGrid_Animation.Size = new Size(364, 380); propertyGrid_Animation.Size = new Size(364, 370);
propertyGrid_Animation.TabIndex = 1; propertyGrid_Animation.TabIndex = 1;
propertyGrid_Animation.ToolbarVisible = false; propertyGrid_Animation.ToolbarVisible = false;
// //
@@ -241,7 +232,7 @@
tabPage_Debug.Controls.Add(propertyGrid_Debug); tabPage_Debug.Controls.Add(propertyGrid_Debug);
tabPage_Debug.Location = new Point(4, 4); tabPage_Debug.Location = new Point(4, 4);
tabPage_Debug.Name = "tabPage_Debug"; tabPage_Debug.Name = "tabPage_Debug";
tabPage_Debug.Size = new Size(364, 380); tabPage_Debug.Size = new Size(364, 370);
tabPage_Debug.TabIndex = 5; tabPage_Debug.TabIndex = 5;
tabPage_Debug.Text = "调试"; tabPage_Debug.Text = "调试";
// //
@@ -252,16 +243,16 @@
propertyGrid_Debug.Location = new Point(0, 0); propertyGrid_Debug.Location = new Point(0, 0);
propertyGrid_Debug.Name = "propertyGrid_Debug"; propertyGrid_Debug.Name = "propertyGrid_Debug";
propertyGrid_Debug.PropertySort = PropertySort.NoSort; propertyGrid_Debug.PropertySort = PropertySort.NoSort;
propertyGrid_Debug.Size = new Size(364, 380); propertyGrid_Debug.Size = new Size(364, 370);
propertyGrid_Debug.TabIndex = 2; propertyGrid_Debug.TabIndex = 2;
propertyGrid_Debug.ToolbarVisible = false; propertyGrid_Debug.ToolbarVisible = false;
// //
// SpinePropertyGrid // SpineViewPropertyGrid
// //
AutoScaleDimensions = new SizeF(11F, 24F); AutoScaleDimensions = new SizeF(11F, 24F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
Controls.Add(tabControl); Controls.Add(tabControl);
Name = "SpinePropertyGrid"; Name = "SpineViewPropertyGrid";
Size = new Size(372, 448); Size = new Size(372, 448);
tabControl.ResumeLayout(false); tabControl.ResumeLayout(false);
tabPage_BaseInfo.ResumeLayout(false); tabPage_BaseInfo.ResumeLayout(false);
@@ -290,8 +281,7 @@
private PropertyGrid propertyGrid_Animation; private PropertyGrid propertyGrid_Animation;
private ContextMenuStrip contextMenuStrip_Skin; private ContextMenuStrip contextMenuStrip_Skin;
private ContextMenuStrip contextMenuStrip_Animation; private ContextMenuStrip contextMenuStrip_Animation;
private ToolStripMenuItem toolStripMenuItem_AddSkin; private ToolStripMenuItem toolStripMenuItem_ReloadSkins;
private ToolStripMenuItem toolStripMenuItem_RemoveSkin;
private ToolStripMenuItem toolStripMenuItem_AddAnimation; private ToolStripMenuItem toolStripMenuItem_AddAnimation;
private ToolStripMenuItem toolStripMenuItem_RemoveAnimation; private ToolStripMenuItem toolStripMenuItem_RemoveAnimation;
private TabPage tabPage_Debug; private TabPage tabPage_Debug;

View File

@@ -51,20 +51,6 @@ namespace SpineViewer.Controls
} }
private SpineObjectProperty[]? selectedSpines = null; private SpineObjectProperty[]? selectedSpines = null;
private void contextMenuStrip_Skin_Opening(object sender, CancelEventArgs e)
{
if (selectedSpines?.Length == 1)
{
toolStripMenuItem_AddSkin.Enabled = true;
toolStripMenuItem_RemoveSkin.Enabled = propertyGrid_Skin.SelectedGridItem.Value is SkinNameProperty;
}
else
{
toolStripMenuItem_AddSkin.Enabled = false;
toolStripMenuItem_RemoveSkin.Enabled = false;
}
}
private void contextMenuStrip_Animation_Opening(object sender, CancelEventArgs e) private void contextMenuStrip_Animation_Opening(object sender, CancelEventArgs e)
{ {
if (selectedSpines?.Length == 1) if (selectedSpines?.Length == 1)
@@ -79,31 +65,10 @@ namespace SpineViewer.Controls
} }
} }
private void toolStripMenuItem_AddSkin_Click(object sender, EventArgs e) private void toolStripMenuItem_ReloadSkins_Click(object sender, EventArgs e)
{ {
if (selectedSpines?.Length != 1) return; foreach (var sp in selectedSpines)
sp.Spine.ReloadSkins();
var spine = selectedSpines[0].Skin.Spine;
if (spine.SkinNames.Length <= 0)
{
MessagePopup.Info("没有可用的皮肤");
return;
}
spine.LoadSkin(spine.SkinNames[0]);
propertyGrid_Skin.Refresh();
}
private void toolStripMenuItem_RemoveSkin_Click(object sender, EventArgs e)
{
if (selectedSpines?.Length != 1) return;
if (propertyGrid_Skin.SelectedGridItem.Value is SkinNameProperty wrapper)
{
selectedSpines[0].Skin.Spine.UnloadSkin(wrapper.Index);
propertyGrid_Skin.Refresh();
}
} }
private void toolStripMenuItem_AddAnimation_Click(object sender, EventArgs e) private void toolStripMenuItem_AddAnimation_Click(object sender, EventArgs e)

View File

@@ -345,32 +345,19 @@ namespace SpineViewer.Spine
protected readonly Dictionary<string, bool> skinLoadStatus = []; protected readonly Dictionary<string, bool> skinLoadStatus = [];
/// <summary> /// <summary>
/// 查询皮肤是否被加载, 皮肤不存在时返回 false /// 查询皮肤加载状态, 皮肤不存在时返回 false
/// </summary> /// </summary>
public bool GetSkinStatus(string name) { lock (_lock) return skinLoadStatus.TryGetValue(name, out var status) && status; } public bool GetSkinStatus(string name) { lock (_lock) return skinLoadStatus.TryGetValue(name, out var status) && status; }
/// <summary> /// <summary>
/// 加载指定皮肤, 如果不存在则忽略, 允许重复加载 /// 设置皮肤加载状态, 忽略不存在的皮肤
/// </summary> /// </summary>
public void LoadSkin(string name) public void SetSkinStatus(string name, bool status)
{ {
if (!skinLoadStatus.ContainsKey(name)) return; if (!skinLoadStatus.ContainsKey(name)) return;
lock (_lock) lock (_lock)
{ {
skinLoadStatus[name] = true; skinLoadStatus[name] = status;
reloadSkins();
}
}
/// <summary>
/// 卸载指定皮肤, 如果不存在则忽略, 允许重复卸载
/// </summary>
public void UnloadSkin(string name)
{
if (!skinLoadStatus.ContainsKey(name)) return;
lock (_lock)
{
skinLoadStatus[name] = false;
reloadSkins(); reloadSkins();
} }
} }

View File

@@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace SpineViewer.Spine.SpineView namespace SpineViewer.Spine.SpineView
{ {
/// <summary> /// <summary>
/// 皮肤列表动态类型包装类, 用于提供对 Spine 皮肤列表的管理能力 /// 皮肤动态类型包装类, 用于提供对 Spine 皮肤的管理能力
/// </summary> /// </summary>
/// <param name="spine">关联的 Spine 对象</param> /// <param name="spine">关联的 Spine 对象</param>
public class SpineSkinProperty(SpineObject spine) : ICustomTypeDescriptor public class SpineSkinProperty(SpineObject spine) : ICustomTypeDescriptor
@@ -18,34 +18,10 @@ namespace SpineViewer.Spine.SpineView
[Browsable(false)] [Browsable(false)]
public SpineObject Spine { get; } = spine; public SpineObject Spine { get; } = spine;
/// <summary>
/// <see cref="SpineSkinProperty"/> 属性缓存
/// </summary>
private readonly Dictionary<int, SkinNameProperty> skinNameProperties = [];
/// <summary>
/// <c>this.Skin{i}</c>
/// </summary>
public SkinNameProperty GetSkinName(int i)
{
if (!skinNameProperties.ContainsKey(i))
skinNameProperties[i] = new SkinNameProperty(Spine, i);
return skinNameProperties[i];
}
/// <summary>
/// <c>this.Skin{i} = <paramref name="value"/></c>
/// </summary>
public void SetSkinName(int i, string value)
{
Spine.ReplaceSkin(i, value);
TypeDescriptor.Refresh(this);
}
/// <summary> /// <summary>
/// 在属性面板悬停可以显示已加载的皮肤列表 /// 在属性面板悬停可以显示已加载的皮肤列表
/// </summary> /// </summary>
public override string ToString() => $"[{string.Join(", ", Spine.GetLoadedSkins())}]"; public override string ToString() => $"[{string.Join(", ", Spine.SkinNames.Where(Spine.GetSkinStatus))}]";
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
@@ -59,7 +35,7 @@ namespace SpineViewer.Spine.SpineView
// XXX: 必须实现 ICustomTypeDescriptor 接口, 不能继承 CustomTypeDescriptor, 似乎继承下来的东西会有问题, 导致某些调用不正确 // XXX: 必须实现 ICustomTypeDescriptor 接口, 不能继承 CustomTypeDescriptor, 似乎继承下来的东西会有问题, 导致某些调用不正确
private static readonly Dictionary<int, SkinNamePropertyDescriptor> pdCache = []; private static readonly Dictionary<string, SkinPropertyDescriptor> pdCache = [];
public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true);
public string? GetClassName() => TypeDescriptor.GetClassName(this, true); public string? GetClassName() => TypeDescriptor.GetClassName(this, true);
@@ -75,112 +51,46 @@ namespace SpineViewer.Spine.SpineView
public PropertyDescriptorCollection GetProperties(Attribute[]? attributes) public PropertyDescriptorCollection GetProperties(Attribute[]? attributes)
{ {
var props = new PropertyDescriptorCollection(TypeDescriptor.GetProperties(this, attributes, true).Cast<PropertyDescriptor>().ToArray()); var props = new PropertyDescriptorCollection(TypeDescriptor.GetProperties(this, attributes, true).Cast<PropertyDescriptor>().ToArray());
for (var i = 0; i < Spine.GetLoadedSkins().Length; i++) foreach (var name in Spine.SkinNames)
{ {
if (!pdCache.ContainsKey(i)) if (!pdCache.ContainsKey(name))
pdCache[i] = new SkinNamePropertyDescriptor(i, [new DisplayNameAttribute($"皮肤 {i}")]); pdCache[name] = new SkinPropertyDescriptor(name, [new DisplayNameAttribute(name)]);
props.Add(pdCache[i]); props.Add(pdCache[name]);
} }
return props; return props;
} }
/// <summary> /// <summary>
/// 皮肤属性描述符, 实现对属性的读取和赋值 /// 皮肤属性描述符, 实现对皮肤的加载和卸载, <c><see cref="SpineSkinProperty"/>.Skin_{name}</c>
/// </summary> /// </summary>
private class SkinNamePropertyDescriptor(int i, Attribute[]? attributes) : PropertyDescriptor($"Skin{i}", attributes) private class SkinPropertyDescriptor(string name, Attribute[]? attributes) : PropertyDescriptor($"Skin_{name}", attributes)
{ {
private readonly int idx = i; private readonly string name = name;
public override Type ComponentType => typeof(SpineSkinProperty); public override Type ComponentType => typeof(SpineSkinProperty);
public override bool IsReadOnly => false; public override bool IsReadOnly => false;
public override Type PropertyType => typeof(SkinNameProperty); public override Type PropertyType => typeof(bool);
public override bool CanResetValue(object component) => false; public override bool CanResetValue(object component) => false;
public override void ResetValue(object component) { } public override void ResetValue(object component) { }
public override bool ShouldSerializeValue(object component) => false; public override bool ShouldSerializeValue(object component) => false;
/// <summary>
/// 得到一个 <see cref="SpineSkinProperty"/>, 允许用户查看或者修改具体的属性值, 这个地方决定了在面板上看到的是一个对象及其属性
/// </summary>
public override object? GetValue(object? component) public override object? GetValue(object? component)
{ {
if (component is SpineSkinProperty prop) if (component is SpineSkinProperty prop)
return prop.GetSkinName(idx); return prop.Spine.GetSkinStatus(name);
return null; return null;
} }
/// <summary>
/// 允许通过字符串赋值修改该位置的皮肤
/// </summary>
public override void SetValue(object? component, object? value) public override void SetValue(object? component, object? value)
{ {
if (component is SpineSkinProperty prop) if (component is SpineSkinProperty prop)
{ {
if (value is string s) if (value is bool s)
prop.SetSkinName(idx, s); prop.Spine.SetSkinStatus(name, s);
} }
} }
} }
#endregion #endregion
} }
/// <summary>
/// 对 <c><see cref="SpineSkinProperty"/>.Skin{i}</c> 属性的包装类
/// </summary>
[TypeConverter(typeof(SkinNamePropertyConverter))]
public class SkinNameProperty(SpineObject spine, int i)
{
private readonly SpineObject spine = spine;
[Browsable(false)]
public int Index { get; } = i;
public override string ToString()
{
var loadedSkins = spine.GetLoadedSkins();
if (Index >= 0 && Index < loadedSkins.Length)
return loadedSkins[Index];
return "!NULL"; // XXX: 预期应该不会发生
}
public override bool Equals(object? obj)
{
if (obj is SkinNameProperty) return ToString() == obj.ToString();
return base.Equals(obj);
}
public override int GetHashCode() => HashCode.Combine(typeof(SkinNameProperty).FullName.GetHashCode(), ToString().GetHashCode());
}
public class SkinNamePropertyConverter : StringConverter
{
// NOTE: 可以不用实现 ConvertTo/ConvertFrom, 因为属性实现了与字符串之间的互转
// ToString 实现了 ConvertTo
// SetValue 实现了从字符串设置属性
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true;
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => true;
public override StandardValuesCollection? GetStandardValues(ITypeDescriptorContext? context)
{
if (context?.Instance is SpineSkinProperty manager)
{
return new StandardValuesCollection(manager.Spine.SkinNames);
}
else if (context?.Instance is object[] instances && instances.All(x => x is SpineSkinProperty))
{
// XXX: 这里不知道为啥总是会得到 object[] 类型而不是具体的 SpineSkinWrapper[] 类型
var managers = instances.Cast<SpineSkinProperty>().ToArray();
if (managers.Length > 0)
{
IEnumerable<string> common = managers[0].Spine.SkinNames;
foreach (var t in managers.Skip(1))
common = common.Union(t.Spine.SkinNames);
return new StandardValuesCollection(common.ToArray());
}
}
return base.GetStandardValues(context);
}
}
} }