diff --git a/SpineViewer/Controls/SpineViewPropertyGrid.Designer.cs b/SpineViewer/Controls/SpineViewPropertyGrid.Designer.cs index 2b0385b..6c45a72 100644 --- a/SpineViewer/Controls/SpineViewPropertyGrid.Designer.cs +++ b/SpineViewer/Controls/SpineViewPropertyGrid.Designer.cs @@ -39,8 +39,7 @@ tabPage_Skin = new TabPage(); propertyGrid_Skin = new PropertyGrid(); contextMenuStrip_Skin = new ContextMenuStrip(components); - toolStripMenuItem_AddSkin = new ToolStripMenuItem(); - toolStripMenuItem_RemoveSkin = new ToolStripMenuItem(); + toolStripMenuItem_ReloadSkins = new ToolStripMenuItem(); tabPage_Animation = new TabPage(); propertyGrid_Animation = new PropertyGrid(); contextMenuStrip_Animation = new ContextMenuStrip(components); @@ -108,7 +107,7 @@ tabPage_Render.Location = new Point(4, 4); tabPage_Render.Margin = new Padding(0); 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.Text = "渲染"; // @@ -119,7 +118,7 @@ propertyGrid_Render.Location = new Point(0, 0); propertyGrid_Render.Name = "propertyGrid_Render"; 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.ToolbarVisible = false; // @@ -130,7 +129,7 @@ tabPage_Transform.Location = new Point(4, 4); tabPage_Transform.Margin = new Padding(0); 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.Text = "变换"; // @@ -141,7 +140,7 @@ propertyGrid_Transform.Location = new Point(0, 0); propertyGrid_Transform.Name = "propertyGrid_Transform"; 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.ToolbarVisible = false; // @@ -152,7 +151,7 @@ tabPage_Skin.Location = new Point(4, 4); tabPage_Skin.Margin = new Padding(0); 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.Text = "皮肤"; // @@ -164,31 +163,23 @@ propertyGrid_Skin.Location = new Point(0, 0); propertyGrid_Skin.Name = "propertyGrid_Skin"; 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.ToolbarVisible = false; // // contextMenuStrip_Skin // 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.Size = new Size(117, 64); - contextMenuStrip_Skin.Opening += contextMenuStrip_Skin_Opening; + contextMenuStrip_Skin.Size = new Size(225, 34); // - // toolStripMenuItem_AddSkin + // toolStripMenuItem_ReloadSkins // - toolStripMenuItem_AddSkin.Name = "toolStripMenuItem_AddSkin"; - toolStripMenuItem_AddSkin.Size = new Size(116, 30); - toolStripMenuItem_AddSkin.Text = "添加"; - toolStripMenuItem_AddSkin.Click += toolStripMenuItem_AddSkin_Click; - // - // toolStripMenuItem_RemoveSkin - // - toolStripMenuItem_RemoveSkin.Name = "toolStripMenuItem_RemoveSkin"; - toolStripMenuItem_RemoveSkin.Size = new Size(116, 30); - toolStripMenuItem_RemoveSkin.Text = "移除"; - toolStripMenuItem_RemoveSkin.Click += toolStripMenuItem_RemoveSkin_Click; + toolStripMenuItem_ReloadSkins.Name = "toolStripMenuItem_ReloadSkins"; + toolStripMenuItem_ReloadSkins.Size = new Size(224, 30); + toolStripMenuItem_ReloadSkins.Text = "重新加载所选皮肤"; + toolStripMenuItem_ReloadSkins.Click += toolStripMenuItem_ReloadSkins_Click; // // tabPage_Animation // @@ -197,7 +188,7 @@ tabPage_Animation.Location = new Point(4, 4); tabPage_Animation.Margin = new Padding(0); 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.Text = "动画"; // @@ -209,7 +200,7 @@ propertyGrid_Animation.Location = new Point(0, 0); propertyGrid_Animation.Name = "propertyGrid_Animation"; 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.ToolbarVisible = false; // @@ -241,7 +232,7 @@ tabPage_Debug.Controls.Add(propertyGrid_Debug); tabPage_Debug.Location = new Point(4, 4); 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.Text = "调试"; // @@ -252,16 +243,16 @@ propertyGrid_Debug.Location = new Point(0, 0); propertyGrid_Debug.Name = "propertyGrid_Debug"; 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.ToolbarVisible = false; // - // SpinePropertyGrid + // SpineViewPropertyGrid // AutoScaleDimensions = new SizeF(11F, 24F); AutoScaleMode = AutoScaleMode.Font; Controls.Add(tabControl); - Name = "SpinePropertyGrid"; + Name = "SpineViewPropertyGrid"; Size = new Size(372, 448); tabControl.ResumeLayout(false); tabPage_BaseInfo.ResumeLayout(false); @@ -290,8 +281,7 @@ private PropertyGrid propertyGrid_Animation; private ContextMenuStrip contextMenuStrip_Skin; private ContextMenuStrip contextMenuStrip_Animation; - private ToolStripMenuItem toolStripMenuItem_AddSkin; - private ToolStripMenuItem toolStripMenuItem_RemoveSkin; + private ToolStripMenuItem toolStripMenuItem_ReloadSkins; private ToolStripMenuItem toolStripMenuItem_AddAnimation; private ToolStripMenuItem toolStripMenuItem_RemoveAnimation; private TabPage tabPage_Debug; diff --git a/SpineViewer/Controls/SpineViewPropertyGrid.cs b/SpineViewer/Controls/SpineViewPropertyGrid.cs index 38e2397..85ddec4 100644 --- a/SpineViewer/Controls/SpineViewPropertyGrid.cs +++ b/SpineViewer/Controls/SpineViewPropertyGrid.cs @@ -51,20 +51,6 @@ namespace SpineViewer.Controls } 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) { 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; - - 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(); - } + foreach (var sp in selectedSpines) + sp.Spine.ReloadSkins(); } private void toolStripMenuItem_AddAnimation_Click(object sender, EventArgs e) diff --git a/SpineViewer/Spine/SpineObject.cs b/SpineViewer/Spine/SpineObject.cs index 6464038..7eae6d8 100644 --- a/SpineViewer/Spine/SpineObject.cs +++ b/SpineViewer/Spine/SpineObject.cs @@ -345,32 +345,19 @@ namespace SpineViewer.Spine protected readonly Dictionary skinLoadStatus = []; /// - /// 查询皮肤是否被加载, 皮肤不存在时返回 false + /// 查询皮肤加载状态, 皮肤不存在时返回 false /// public bool GetSkinStatus(string name) { lock (_lock) return skinLoadStatus.TryGetValue(name, out var status) && status; } /// - /// 加载指定皮肤, 如果不存在则忽略, 允许重复加载 + /// 设置皮肤加载状态, 忽略不存在的皮肤 /// - public void LoadSkin(string name) + public void SetSkinStatus(string name, bool status) { if (!skinLoadStatus.ContainsKey(name)) return; lock (_lock) { - skinLoadStatus[name] = true; - reloadSkins(); - } - } - - /// - /// 卸载指定皮肤, 如果不存在则忽略, 允许重复卸载 - /// - public void UnloadSkin(string name) - { - if (!skinLoadStatus.ContainsKey(name)) return; - lock (_lock) - { - skinLoadStatus[name] = false; + skinLoadStatus[name] = status; reloadSkins(); } } diff --git a/SpineViewer/Spine/SpineView/SpineSkinProperty.cs b/SpineViewer/Spine/SpineView/SpineSkinProperty.cs index cc9b2b7..0b4635d 100644 --- a/SpineViewer/Spine/SpineView/SpineSkinProperty.cs +++ b/SpineViewer/Spine/SpineView/SpineSkinProperty.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace SpineViewer.Spine.SpineView { /// - /// 皮肤列表动态类型包装类, 用于提供对 Spine 皮肤列表的管理能力 + /// 皮肤动态类型包装类, 用于提供对 Spine 皮肤的管理能力 /// /// 关联的 Spine 对象 public class SpineSkinProperty(SpineObject spine) : ICustomTypeDescriptor @@ -18,34 +18,10 @@ namespace SpineViewer.Spine.SpineView [Browsable(false)] public SpineObject Spine { get; } = spine; - /// - /// 属性缓存 - /// - private readonly Dictionary skinNameProperties = []; - - /// - /// this.Skin{i} - /// - public SkinNameProperty GetSkinName(int i) - { - if (!skinNameProperties.ContainsKey(i)) - skinNameProperties[i] = new SkinNameProperty(Spine, i); - return skinNameProperties[i]; - } - - /// - /// this.Skin{i} = - /// - public void SetSkinName(int i, string value) - { - Spine.ReplaceSkin(i, value); - TypeDescriptor.Refresh(this); - } - /// /// 在属性面板悬停可以显示已加载的皮肤列表 /// - 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) { @@ -59,7 +35,7 @@ namespace SpineViewer.Spine.SpineView // XXX: 必须实现 ICustomTypeDescriptor 接口, 不能继承 CustomTypeDescriptor, 似乎继承下来的东西会有问题, 导致某些调用不正确 - private static readonly Dictionary pdCache = []; + private static readonly Dictionary pdCache = []; public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public string? GetClassName() => TypeDescriptor.GetClassName(this, true); @@ -75,112 +51,46 @@ namespace SpineViewer.Spine.SpineView public PropertyDescriptorCollection GetProperties(Attribute[]? attributes) { var props = new PropertyDescriptorCollection(TypeDescriptor.GetProperties(this, attributes, true).Cast().ToArray()); - for (var i = 0; i < Spine.GetLoadedSkins().Length; i++) + foreach (var name in Spine.SkinNames) { - if (!pdCache.ContainsKey(i)) - pdCache[i] = new SkinNamePropertyDescriptor(i, [new DisplayNameAttribute($"皮肤 {i}")]); - props.Add(pdCache[i]); + if (!pdCache.ContainsKey(name)) + pdCache[name] = new SkinPropertyDescriptor(name, [new DisplayNameAttribute(name)]); + props.Add(pdCache[name]); } return props; } /// - /// 皮肤属性描述符, 实现对属性的读取和赋值 + /// 皮肤属性描述符, 实现对皮肤的加载和卸载, .Skin_{name} /// - 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 bool IsReadOnly => false; - public override Type PropertyType => typeof(SkinNameProperty); + public override Type PropertyType => typeof(bool); public override bool CanResetValue(object component) => false; public override void ResetValue(object component) { } public override bool ShouldSerializeValue(object component) => false; - /// - /// 得到一个 , 允许用户查看或者修改具体的属性值, 这个地方决定了在面板上看到的是一个对象及其属性 - /// public override object? GetValue(object? component) { if (component is SpineSkinProperty prop) - return prop.GetSkinName(idx); + return prop.Spine.GetSkinStatus(name); return null; } - /// - /// 允许通过字符串赋值修改该位置的皮肤 - /// public override void SetValue(object? component, object? value) { if (component is SpineSkinProperty prop) { - if (value is string s) - prop.SetSkinName(idx, s); + if (value is bool s) + prop.Spine.SetSkinStatus(name, s); } } } #endregion } - - /// - /// 对 .Skin{i} 属性的包装类 - /// - [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().ToArray(); - if (managers.Length > 0) - { - IEnumerable 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); - } - } }