增加预览图

This commit is contained in:
ww-rm
2025-03-19 15:12:05 +08:00
parent 145f4f3265
commit 091301e945
4 changed files with 169 additions and 15 deletions

View File

@@ -41,6 +41,13 @@
toolStripSeparator2 = new ToolStripSeparator();
toolStripMenuItem_BatchAdd = new ToolStripMenuItem();
toolStripMenuItem_RemoveAll = new ToolStripMenuItem();
toolStripSeparator3 = new ToolStripSeparator();
toolStripMenuItem_ChangeView = new ToolStripMenuItem();
toolStripMenuItem_LargeIconView = new ToolStripMenuItem();
toolStripMenuItem_SmallIconView = new ToolStripMenuItem();
toolStripMenuItem_DetailsView = new ToolStripMenuItem();
imageList_LargeIcon = new ImageList(components);
imageList_SmallIcon = new ImageList(components);
contextMenuStrip.SuspendLayout();
SuspendLayout();
//
@@ -52,10 +59,12 @@
listView.Dock = DockStyle.Fill;
listView.FullRowSelect = true;
listView.GridLines = true;
listView.LargeImageList = imageList_LargeIcon;
listView.Location = new Point(0, 0);
listView.Name = "listView";
listView.ShowItemToolTips = true;
listView.Size = new Size(336, 445);
listView.SmallImageList = imageList_SmallIcon;
listView.TabIndex = 1;
listView.UseCompatibleStateImageBehavior = false;
listView.View = View.Details;
@@ -73,9 +82,9 @@
// contextMenuStrip
//
contextMenuStrip.ImageScalingSize = new Size(24, 24);
contextMenuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_Add, toolStripMenuItem_Insert, toolStripMenuItem_Remove, toolStripSeparator1, toolStripMenuItem_MoveUp, toolStripMenuItem_MoveDown, toolStripSeparator2, toolStripMenuItem_BatchAdd, toolStripMenuItem_RemoveAll });
contextMenuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_Add, toolStripMenuItem_Insert, toolStripMenuItem_Remove, toolStripSeparator1, toolStripMenuItem_MoveUp, toolStripMenuItem_MoveDown, toolStripSeparator2, toolStripMenuItem_BatchAdd, toolStripMenuItem_RemoveAll, toolStripSeparator3, toolStripMenuItem_ChangeView });
contextMenuStrip.Name = "contextMenuStrip";
contextMenuStrip.Size = new Size(188, 226);
contextMenuStrip.Size = new Size(188, 262);
contextMenuStrip.Opening += contextMenuStrip_Opening;
//
// toolStripMenuItem_Add
@@ -140,6 +149,51 @@
toolStripMenuItem_RemoveAll.Text = "移除全部(&X)";
toolStripMenuItem_RemoveAll.Click += toolStripMenuItem_RemoveAll_Click;
//
// toolStripSeparator3
//
toolStripSeparator3.Name = "toolStripSeparator3";
toolStripSeparator3.Size = new Size(184, 6);
//
// toolStripMenuItem_ChangeView
//
toolStripMenuItem_ChangeView.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_LargeIconView, toolStripMenuItem_SmallIconView, toolStripMenuItem_DetailsView });
toolStripMenuItem_ChangeView.Name = "toolStripMenuItem_ChangeView";
toolStripMenuItem_ChangeView.Size = new Size(187, 30);
toolStripMenuItem_ChangeView.Text = "切换视图";
//
// toolStripMenuItem_LargeIconView
//
toolStripMenuItem_LargeIconView.Name = "toolStripMenuItem_LargeIconView";
toolStripMenuItem_LargeIconView.Size = new Size(164, 34);
toolStripMenuItem_LargeIconView.Text = "大图标";
toolStripMenuItem_LargeIconView.Click += toolStripMenuItem_LargeIconView_Click;
//
// toolStripMenuItem_SmallIconView
//
toolStripMenuItem_SmallIconView.Name = "toolStripMenuItem_SmallIconView";
toolStripMenuItem_SmallIconView.Size = new Size(164, 34);
toolStripMenuItem_SmallIconView.Text = "小图标";
toolStripMenuItem_SmallIconView.Click += toolStripMenuItem_SmallIconView_Click;
//
// toolStripMenuItem_DetailsView
//
toolStripMenuItem_DetailsView.Name = "toolStripMenuItem_DetailsView";
toolStripMenuItem_DetailsView.Size = new Size(164, 34);
toolStripMenuItem_DetailsView.Text = "列表";
toolStripMenuItem_DetailsView.Click += toolStripMenuItem_DetailsView_Click;
//
// imageList_LargeIcon
//
imageList_LargeIcon.ColorDepth = ColorDepth.Depth32Bit;
imageList_LargeIcon.ImageSize = new Size(96, 96);
imageList_LargeIcon.TransparentColor = Color.Transparent;
//
// imageList_SmallIcon
//
imageList_SmallIcon.ColorDepth = ColorDepth.Depth32Bit;
imageList_SmallIcon.ImageSize = new Size(48, 48);
imageList_SmallIcon.TransparentColor = Color.Transparent;
//
// SpineListView
//
AutoScaleDimensions = new SizeF(11F, 24F);
@@ -164,5 +218,12 @@
private ToolStripMenuItem toolStripMenuItem_MoveDown;
private ToolStripSeparator toolStripSeparator2;
private ColumnHeader columnHeader_Name;
private ImageList imageList_SmallIcon;
private ImageList imageList_LargeIcon;
private ToolStripSeparator toolStripSeparator3;
private ToolStripMenuItem toolStripMenuItem_ChangeView;
private ToolStripMenuItem toolStripMenuItem_LargeIconView;
private ToolStripMenuItem toolStripMenuItem_SmallIconView;
private ToolStripMenuItem toolStripMenuItem_DetailsView;
}
}

View File

@@ -58,8 +58,13 @@ namespace SpineViewer.Controls
index = listView.Items.Count;
// 锁定外部的读操作
lock (Spines) { spines.Insert(index, spine); }
listView.Items.Insert(index, new ListViewItem(spine.Name) { ToolTipText = spine.SkelPath });
lock (Spines)
{
spines.Insert(index, spine);
listView.SmallImageList.Images.Add(spine.ID, spine.Preview);
listView.LargeImageList.Images.Add(spine.ID, spine.Preview);
}
listView.Items.Insert(index, new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
// 选中新增项
listView.SelectedIndices.Clear();
@@ -123,8 +128,14 @@ namespace SpineViewer.Controls
try
{
var spine = Spine.Spine.New(version, skelPath);
var preview = spine.Preview;
lock (Spines) { spines.Add(spine); }
listView.Invoke(() => listView.Items.Add(new ListViewItem(spine.Name) { ToolTipText = spine.SkelPath }));
listView.Invoke(() =>
{
listView.SmallImageList.Images.Add(spine.ID, preview);
listView.LargeImageList.Images.Add(spine.ID, preview);
listView.Items.Add(new ListViewItem(spine.Name, spine.ID) { ToolTipText = spine.SkelPath });
});
success++;
}
catch (Exception ex)
@@ -255,6 +266,11 @@ namespace SpineViewer.Controls
toolStripMenuItem_MoveUp.Enabled = selectedCount == 1 && listView.SelectedIndices[0] != 0;
toolStripMenuItem_MoveDown.Enabled = selectedCount == 1 && listView.SelectedIndices[0] != itemsCount - 1;
toolStripMenuItem_RemoveAll.Enabled = itemsCount > 0;
// 视图选项
toolStripMenuItem_LargeIconView.Checked = listView.View == View.LargeIcon;
toolStripMenuItem_SmallIconView.Checked = listView.View == View.SmallIcon;
toolStripMenuItem_DetailsView.Checked = listView.View == View.Details;
}
private void toolStripMenuItem_Add_Click(object sender, EventArgs e)
@@ -288,8 +304,11 @@ namespace SpineViewer.Controls
{
lock (Spines)
{
spines[i].Dispose();
var spine = spines[i];
spines.RemoveAt(i);
listView.SmallImageList.Images.RemoveByKey(spine.ID);
listView.LargeImageList.Images.RemoveByKey(spine.ID);
spine.Dispose();
}
listView.Items.RemoveAt(i);
}
@@ -338,10 +357,27 @@ namespace SpineViewer.Controls
foreach (var spine in spines)
spine.Dispose();
spines.Clear();
listView.SmallImageList.Images.Clear();
listView.LargeImageList.Images.Clear();
}
listView.Items.Clear();
if (PropertyGrid is not null)
PropertyGrid.SelectedObject = null;
}
private void toolStripMenuItem_LargeIconView_Click(object sender, EventArgs e)
{
listView.View = View.LargeIcon;
}
private void toolStripMenuItem_SmallIconView_Click(object sender, EventArgs e)
{
listView.View = View.SmallIcon;
}
private void toolStripMenuItem_DetailsView_Click(object sender, EventArgs e)
{
listView.View = View.Details;
}
}
}

View File

@@ -120,4 +120,10 @@
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="imageList_LargeIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>552, 29</value>
</metadata>
<metadata name="imageList_SmallIcon.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>267, 34</value>
</metadata>
</root>

View File

@@ -41,6 +41,16 @@ namespace SpineViewer.Spine
/// </summary>
public const string EMPTY_ANIMATION = "<Empty>";
/// <summary>
/// 预览图大小
/// </summary>
public static readonly Size PREVIEW_SIZE = new(256, 256);
/// <summary>
/// 缩放最小值
/// </summary>
public const float SCALE_MIN = 0.001f;
/// <summary>
/// 实现类缓存
/// </summary>
@@ -108,6 +118,11 @@ namespace SpineViewer.Spine
return (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
}
/// <summary>
/// 标识符
/// </summary>
public readonly string ID = Guid.NewGuid().ToString();
/// <summary>
/// 构造函数
/// </summary>
@@ -132,13 +147,7 @@ namespace SpineViewer.Spine
~Spine() { Dispose(false); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { }
/// <summary>
/// 缩放最小值
/// </summary>
[Browsable(false)]
public const float SCALE_MIN = 0.001f;
protected virtual void Dispose(bool disposing) { preview?.Dispose(); }
/// <summary>
/// 获取所属版本
@@ -231,6 +240,48 @@ namespace SpineViewer.Spine
[Browsable(false)]
public abstract RectangleF Bounds { get; }
/// <summary>
/// 骨骼预览图
/// </summary>
[Browsable(false)]
public Image Preview { get => preview ??= GetPreview(PREVIEW_SIZE); }
private Image preview = null;
public Image GetPreview(Size size)
{
var curAnimation = CurrentAnimation;
CurrentAnimation = EMPTY_ANIMATION;
var bounds = Bounds;
float viewX = size.Width;
float viewY = size.Height;
float sizeX = bounds.Width;
float sizeY = bounds.Height;
var scale = 1f;
if ((sizeY / sizeX) < (viewY / viewX))
scale = sizeX / viewX;// 相同的 X, 视窗 Y 更大
else
scale = sizeY / viewY;// 相同的 Y, 视窗 X 更大
viewX *= scale;
viewY *= scale;
var tex = new SFML.Graphics.RenderTexture((uint)size.Width, (uint)size.Height);
var view = tex.GetView();
view.Center = new(bounds.X + viewX / 2, bounds.Y + viewY / 2);
view.Size = new(viewX, -viewY);
tex.SetView(view);
tex.Clear(SFML.Graphics.Color.Transparent);
tex.Draw(this);
tex.Display();
CurrentAnimation = curAnimation;
using var img = tex.Texture.CopyToImage();
img.SaveToMemory(out var imgBuffer, "bmp");
using var stream = new MemoryStream(imgBuffer);
return new Bitmap(stream);
}
/// <summary>
/// 获取动画时长, 如果动画不存在则返回 0
/// </summary>