Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e293daf62 | ||
|
|
f9d7fdc516 | ||
|
|
6a04f3955c | ||
|
|
dce3b1780c | ||
|
|
f47f3e9db6 | ||
|
|
4ac74acaf7 | ||
|
|
cf7588c288 | ||
|
|
ec7bdf4000 | ||
|
|
51cd97f782 | ||
|
|
a16f2f096d | ||
|
|
4e92f14551 | ||
|
|
8f6cc9ff44 | ||
|
|
f885df5c67 |
@@ -1,5 +1,14 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.10.9
|
||||
|
||||
- 预览图导出增加名称后缀参数
|
||||
|
||||
## v0.10.8
|
||||
|
||||
- 完善预览图导出
|
||||
- 优化骨骼文件选择
|
||||
|
||||
## v0.10.7
|
||||
|
||||
- 增加仅导出选中
|
||||
|
||||
90
README.en.md
90
README.en.md
@@ -4,7 +4,7 @@
|
||||
|
||||
[中文](README.md) | [English](README.en.md)
|
||||
|
||||
A simple and user-friendly Spine file viewer and exporter.
|
||||
A simple and user-friendly tool for viewing and exporting Spine files.
|
||||
|
||||

|
||||
|
||||
@@ -12,59 +12,81 @@ A simple and user-friendly Spine file viewer and exporter.
|
||||
|
||||
## Installation
|
||||
|
||||
Download the zip package from the [Releases](https://github.com/ww-rm/SpineViewer/releases) page.
|
||||
Go to the [Release](https://github.com/ww-rm/SpineViewer/releases) page to download the compressed package.
|
||||
|
||||
The application requires the [.NET Desktop Runtime 8.0.x](https://dotnet.microsoft.com/en-us/download/dotnet/8.0).
|
||||
The software requires the dependency framework [.NET Desktop Runtime 8.0.x](https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0).
|
||||
|
||||
Alternatively, you can download the zip package with the `SelfContained` suffix, which can run independently.
|
||||
You can also download the package with the `SelfContained` suffix, which can run independently.
|
||||
|
||||
## Features
|
||||
## Version Support
|
||||
|
||||
- Supports viewing Spine files of different versions:
|
||||
- [x] `v2.1.x`
|
||||
- [x] `v3.6.x`
|
||||
- [x] `v3.7.x`
|
||||
- [x] `v3.8.x`
|
||||
- [x] `v4.0.x`
|
||||
- [x] `v4.1.x`
|
||||
- [x] `v4.2.x`
|
||||
- [ ] `v4.3.x`
|
||||
- Supports animation preview for multi-skeleton files
|
||||
- Allows independent parameter settings for each skeleton
|
||||
- Supports exporting animation as PNG frame sequences
|
||||
- Provides export settings such as zoom and rotation
|
||||
- More features coming soon...
|
||||
| Version | View & Export | Format Conversion | Version Conversion |
|
||||
| :-------: | :--------------------: | :--------------------: | :----------------: |
|
||||
| `2.1.x` | :white_check_mark: | | |
|
||||
| `3.1.x` | | | |
|
||||
| `3.4.x` | | | |
|
||||
| `3.5.x` | | | |
|
||||
| `3.6.x` | :white_check_mark: | | |
|
||||
| `3.7.x` | :white_check_mark: | | |
|
||||
| `3.8.x` | :white_check_mark: | :white_check_mark: | |
|
||||
| `4.1.x` | :white_check_mark: | | |
|
||||
| `4.2.x` | :white_check_mark: | | |
|
||||
| `4.3.x` | | | |
|
||||
|
||||
## Usage
|
||||
|
||||
### Importing Skeletons
|
||||
|
||||
Use the **File** menu to select **Open** or **Batch Open** to import skeleton files.
|
||||
There are 3 ways to import skeleton files:
|
||||
|
||||
### Adjusting Skeletons
|
||||
- **Drag & Drop/Paste:**
|
||||
Drag and drop or paste the skeleton file/directory into the model list.
|
||||
This method automatically searches through the provided files and subdirectories. Although convenient, it relies on the file structure and has its limitations.
|
||||
|
||||
- Only standard files with `*.json`, `*.skel`, or `.atlas` extensions are automatically detected.
|
||||
- The skeleton file and atlas file must have the same name.
|
||||
- The version string in the skeleton file must not be modified.
|
||||
|
||||
Select one or more items in the **Model List** to display adjustable parameters in the **Model Parameters** panel.
|
||||
- **Batch Open from the File Menu:**
|
||||
This method offers more file flexibility. You can drag and drop or paste files into the file selection dialog, and additional options are available.
|
||||
|
||||
- The filename restrictions are similar to the above, but you can use the panel’s file selection button to choose skeleton files with non-standard extensions.
|
||||
- You can set a fixed load version to handle cases where the version number has been modified.
|
||||
|
||||
Right-clicking in the **Model List** allows you to add, delete, or adjust list items. You can also drag items with the left mouse button to rearrange them.
|
||||
- **Open a Single Model:**
|
||||
This method offers the highest degree of freedom, allowing you to select any skeleton file and atlas file without filename restrictions. You can also set the load version.
|
||||
|
||||
### Adjusting the View
|
||||
### Adjusting Preview Content
|
||||
|
||||
Mouse operations supported in the **Preview** window:
|
||||
The model list supports right-click menus and various shortcut keys, and you can select multiple models to adjust their parameters in bulk.
|
||||
|
||||
- Left-click to drag the skeleton
|
||||
- Right-click to drag the view
|
||||
- Scroll wheel to zoom in/out
|
||||
In addition to the parameter panel, the preview area supports several mouse actions:
|
||||
|
||||
Additionally, you can adjust export and preview parameters through the **View Parameters** panel.
|
||||
- **Left-click:** Select and drag models. Holding down the `Ctrl` key enables multi-selection, which syncs with the model list.
|
||||
- **Right-click:** Drag the overall canvas.
|
||||
- **Scroll wheel:** Zoom the view.
|
||||
- **Selective Rendering:** The preview area supports a mode to render only the selected models. In this mode, only the selected models are displayed, and selection changes must be made through the model list.
|
||||
|
||||
In the **Functions** menu, you can reset and synchronize the animation time for all skeletons.
|
||||
In the function menu, you can reset and synchronize the animation time for all skeletons.
|
||||
|
||||
### Exporting Animations
|
||||
### Exporting Preview Content
|
||||
|
||||
Select **Export** from the **File** menu to export all loaded skeleton animations as PNG frame sequences, based on the current preview settings.
|
||||
Both preview images and videos can be exported.
|
||||
|
||||
You can view the full duration of each animation in the **Model Parameters** of each skeleton.
|
||||
- **Preview Image:**
|
||||
The exported preview image shows the model in its default state, with one image per model.
|
||||
|
||||
- **Video (TODO: Currently only supports frame sequence export):**
|
||||
The complete animation duration for each skeleton can be viewed in the model parameters.
|
||||
|
||||
When the preview area is set to render only the selected models, the exported content will include only the models that are displayed.
|
||||
|
||||
### Format & Version Conversion
|
||||
|
||||
You can use the tools menu to convert skeleton files. This feature supports conversion between binary and text formats, as well as between different versions.
|
||||
|
||||
Currently under development, it only supports converting `3.8.x` binary format to text format.
|
||||
|
||||
---
|
||||
|
||||
*If you find this project helpful, please give it a :star: and share it with others! :)*
|
||||
*If you like this project, please give it a :star: and share it with more people! :)*
|
||||
|
||||
86
README.md
86
README.md
@@ -18,62 +18,72 @@
|
||||
|
||||
也可以下载带有 `SelfContained` 后缀的压缩包, 可以独立运行.
|
||||
|
||||
## 功能支持
|
||||
## 版本支持
|
||||
|
||||
| 版本 | 查看&导出 | 格式转换 |
|
||||
| :---: | :---: | :---: |
|
||||
| `2.1.x` | :white_check_mark: | |
|
||||
| `3.1.x` | | |
|
||||
| `3.4.x` | | |
|
||||
| `3.5.x` | | |
|
||||
| `3.6.x` | :white_check_mark: | |
|
||||
| `3.7.x` | :white_check_mark: | |
|
||||
| `3.8.x` | :white_check_mark: | :white_check_mark: |
|
||||
| `4.1.x` | :white_check_mark: | |
|
||||
| `4.2.x` | :white_check_mark: | |
|
||||
| `4.3.x` | | |
|
||||
|
||||
- 支持文件拖放/复制到剪贴板打开
|
||||
- 支持自动检测版本
|
||||
- 支持列表缩略图预览
|
||||
- 支持多骨骼文件动画预览
|
||||
- 支持每个骨骼独立参数设置
|
||||
- 支持动画PNG帧序列导出
|
||||
- 支持缩放旋转等导出画面设置
|
||||
- 支持对独立的骨骼文件进行格式转换
|
||||
- Coming soon...
|
||||
| 版本 | 查看&导出 | 格式转换 | 版本转换 |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| `2.1.x` | :white_check_mark: | | |
|
||||
| `3.1.x` | | | |
|
||||
| `3.4.x` | | | |
|
||||
| `3.5.x` | | | |
|
||||
| `3.6.x` | :white_check_mark: | | |
|
||||
| `3.7.x` | :white_check_mark: | | |
|
||||
| `3.8.x` | :white_check_mark: | :white_check_mark: | |
|
||||
| `4.1.x` | :white_check_mark: | | |
|
||||
| `4.2.x` | :white_check_mark: | | |
|
||||
| `4.3.x` | | | |
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 骨骼导入
|
||||
|
||||
**文件**菜单可以选择**打开**或者**批量打开**进行骨骼文件导入.
|
||||
有 3 种模式导入骨骼文件:
|
||||
|
||||
或者直接把要打开的骨骼文件拖进列表, 这种方式只支持 `.json` 和 `.skel` 后缀的文件, 其他的会被忽略.
|
||||
- 拖放/粘贴需要导入的骨骼文件/目录到模型列表
|
||||
|
||||
### 骨骼调整
|
||||
这种方式会自动查找传入的文件列表以及目录内的子级文件列表, 虽然方便但是依赖模型文件结构, 限制最多.
|
||||
|
||||
在**模型列表**中选择一项或多项, 将会在**模型参数**面板显示可供调节的参数.
|
||||
- 仅支持自动发现标准的 `*.json`/`*.skel`/`.atlas` 后缀文件.
|
||||
- 骨骼文件和 atlas 文件需要是同名.
|
||||
- 需要保证骨骼文件里的版本字符串不是魔改过的.
|
||||
- 从文件菜单里批量打开骨骼文件
|
||||
|
||||
**模型列表**右键菜单可以对列表项进行增删调整, 也可以使用鼠标左键拖动调整顺序.
|
||||
这种方式提供一定程度的文件自由度, 文件选择框里同样支持拖放/粘贴, 但是多一些额外选项.
|
||||
|
||||
### 画面调整
|
||||
- 文件名限制条件与上面类似, 但是可以通过面板的选择文件按钮选择非标准后缀的骨骼文件.
|
||||
- 可以设置固定加载版本, 便于应对魔改过的版本号.
|
||||
- 选择单个模型打开
|
||||
|
||||
**预览画面**支持的鼠标操作:
|
||||
这种方式自由度最高, 允许选择任意的骨骼文件和 atlas 文件, 可以没有文件名限制, 并且也可以设置加载版本.
|
||||
|
||||
- 左键可以对骨骼进行拖动
|
||||
- 右键对画面进行拖动
|
||||
- 滚轮进行画面缩放
|
||||
### 预览内容调整
|
||||
|
||||
除此之外, 也可以通过**画面参数**面板调节导出和预览时的画面参数.
|
||||
模型列表支持右键菜单以及部分快捷键, 并且可以多选进行模型参数的批量调整.
|
||||
|
||||
在**功能**菜单中, 可以重置同步所有骨骼动画时间.
|
||||
预览画面除了使用面板进行参数设置外, 支持部分鼠标动作:
|
||||
|
||||
### 动画导出
|
||||
- 左键可以选择和拖拽模型, 按下 `Ctrl` 键可以实现多选, 与左侧列表选择是联动的.
|
||||
- 右键对整体画面进行拖动.
|
||||
- 滚轮进行画面缩放.
|
||||
- 预览画面支持仅渲染选中, 在该模式下, 画面仅显示被选中的模型, 并且只能通过左侧列表改变选中状态.
|
||||
|
||||
**文件**菜单中选择**导出**可以将目前加载的所有骨骼动画按照预览时的画面进行PNG帧序列导出.
|
||||
在功能菜单中, 可以重置同步所有骨骼动画时间.
|
||||
|
||||
可以在每个骨骼的**模型参数**中查看动画完整时长.
|
||||
### 预览内容导出
|
||||
|
||||
支持预览图和视频的导出.
|
||||
|
||||
预览图导出的内容是模型的默认状态画面, 每个模型一张单独的预览图.
|
||||
|
||||
视频(TODO: 目前仅支持帧序列导出), 可以在每个骨骼的模型参数中查看动画完整时长.
|
||||
|
||||
当预览画面处于仅渲染选中状态时, 导出的内容仅包含被选中的模型, 也就是在画面中显示的内容.
|
||||
|
||||
### 格式与版本转换
|
||||
|
||||
可以通过工具菜单进行骨骼文件转换, 允许二进制和文本格式之间的转换, 以及不同版本间的转换.
|
||||
|
||||
目前处于施工中, 仅支持转换 `3.8.x` 二进制到文本格式.
|
||||
|
||||
---
|
||||
|
||||
|
||||
197
SpineViewer/Controls/SkelFileListBox.Designer.cs
generated
Normal file
197
SpineViewer/Controls/SkelFileListBox.Designer.cs
generated
Normal file
@@ -0,0 +1,197 @@
|
||||
namespace SpineViewer.Controls
|
||||
{
|
||||
partial class SkelFileListBox
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
tableLayoutPanel1 = new TableLayoutPanel();
|
||||
flowLayoutPanel1 = new FlowLayoutPanel();
|
||||
button_AddFolder = new Button();
|
||||
button_AddFile = new Button();
|
||||
label_Tip = new Label();
|
||||
listBox = new ListBox();
|
||||
contextMenuStrip = new ContextMenuStrip(components);
|
||||
toolStripMenuItem_SelectAll = new ToolStripMenuItem();
|
||||
toolStripMenuItem_Paste = new ToolStripMenuItem();
|
||||
toolStripMenuItem_Remove = new ToolStripMenuItem();
|
||||
folderBrowserDialog = new FolderBrowserDialog();
|
||||
openFileDialog_Skel = new OpenFileDialog();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
flowLayoutPanel1.SuspendLayout();
|
||||
contextMenuStrip.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
tableLayoutPanel1.ColumnCount = 1;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel1, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(listBox, 0, 1);
|
||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new Point(0, 0);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 2;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Size = new Size(801, 394);
|
||||
tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanel1
|
||||
//
|
||||
flowLayoutPanel1.AutoSize = true;
|
||||
flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
flowLayoutPanel1.Controls.Add(button_AddFolder);
|
||||
flowLayoutPanel1.Controls.Add(button_AddFile);
|
||||
flowLayoutPanel1.Controls.Add(label_Tip);
|
||||
flowLayoutPanel1.Dock = DockStyle.Fill;
|
||||
flowLayoutPanel1.Location = new Point(3, 3);
|
||||
flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||
flowLayoutPanel1.Size = new Size(795, 40);
|
||||
flowLayoutPanel1.TabIndex = 1;
|
||||
//
|
||||
// button_AddFolder
|
||||
//
|
||||
button_AddFolder.AutoSize = true;
|
||||
button_AddFolder.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
button_AddFolder.Location = new Point(3, 3);
|
||||
button_AddFolder.Name = "button_AddFolder";
|
||||
button_AddFolder.Size = new Size(122, 34);
|
||||
button_AddFolder.TabIndex = 0;
|
||||
button_AddFolder.Text = "添加文件夹...";
|
||||
button_AddFolder.UseVisualStyleBackColor = true;
|
||||
button_AddFolder.Click += button_AddFolder_Click;
|
||||
//
|
||||
// button_AddFile
|
||||
//
|
||||
button_AddFile.AutoSize = true;
|
||||
button_AddFile.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
button_AddFile.Location = new Point(131, 3);
|
||||
button_AddFile.Name = "button_AddFile";
|
||||
button_AddFile.Size = new Size(104, 34);
|
||||
button_AddFile.TabIndex = 1;
|
||||
button_AddFile.Text = "添加文件...";
|
||||
button_AddFile.UseVisualStyleBackColor = true;
|
||||
button_AddFile.Click += button_AddFile_Click;
|
||||
//
|
||||
// label_Tip
|
||||
//
|
||||
label_Tip.Anchor = AnchorStyles.Left;
|
||||
label_Tip.AutoSize = true;
|
||||
label_Tip.Location = new Point(241, 8);
|
||||
label_Tip.Name = "label_Tip";
|
||||
label_Tip.Size = new Size(139, 24);
|
||||
label_Tip.TabIndex = 3;
|
||||
label_Tip.Text = "已添加 0 个文件";
|
||||
label_Tip.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// listBox
|
||||
//
|
||||
listBox.AllowDrop = true;
|
||||
listBox.ContextMenuStrip = contextMenuStrip;
|
||||
listBox.Dock = DockStyle.Fill;
|
||||
listBox.FormattingEnabled = true;
|
||||
listBox.HorizontalScrollbar = true;
|
||||
listBox.ItemHeight = 24;
|
||||
listBox.Location = new Point(3, 49);
|
||||
listBox.Name = "listBox";
|
||||
listBox.SelectionMode = SelectionMode.MultiExtended;
|
||||
listBox.Size = new Size(795, 342);
|
||||
listBox.TabIndex = 0;
|
||||
listBox.DragDrop += listBox_DragDrop;
|
||||
listBox.DragEnter += listBox_DragEnter;
|
||||
//
|
||||
// contextMenuStrip
|
||||
//
|
||||
contextMenuStrip.ImageScalingSize = new Size(24, 24);
|
||||
contextMenuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_SelectAll, toolStripMenuItem_Paste, toolStripMenuItem_Remove });
|
||||
contextMenuStrip.Name = "contextMenuStrip";
|
||||
contextMenuStrip.Size = new Size(184, 94);
|
||||
//
|
||||
// toolStripMenuItem_SelectAll
|
||||
//
|
||||
toolStripMenuItem_SelectAll.Name = "toolStripMenuItem_SelectAll";
|
||||
toolStripMenuItem_SelectAll.ShortcutKeys = Keys.Control | Keys.A;
|
||||
toolStripMenuItem_SelectAll.Size = new Size(183, 30);
|
||||
toolStripMenuItem_SelectAll.Text = "全选";
|
||||
toolStripMenuItem_SelectAll.Click += toolStripMenuItem_SelectAll_Click;
|
||||
//
|
||||
// toolStripMenuItem_Paste
|
||||
//
|
||||
toolStripMenuItem_Paste.Name = "toolStripMenuItem_Paste";
|
||||
toolStripMenuItem_Paste.ShortcutKeys = Keys.Control | Keys.V;
|
||||
toolStripMenuItem_Paste.Size = new Size(183, 30);
|
||||
toolStripMenuItem_Paste.Text = "粘贴";
|
||||
toolStripMenuItem_Paste.Click += toolStripMenuItem_Paste_Click;
|
||||
//
|
||||
// toolStripMenuItem_Remove
|
||||
//
|
||||
toolStripMenuItem_Remove.Name = "toolStripMenuItem_Remove";
|
||||
toolStripMenuItem_Remove.ShortcutKeys = Keys.Delete;
|
||||
toolStripMenuItem_Remove.Size = new Size(183, 30);
|
||||
toolStripMenuItem_Remove.Text = "移除";
|
||||
toolStripMenuItem_Remove.Click += toolStripMenuItem_Remove_Click;
|
||||
//
|
||||
// openFileDialog_Skel
|
||||
//
|
||||
openFileDialog_Skel.AddExtension = false;
|
||||
openFileDialog_Skel.AddToRecent = false;
|
||||
openFileDialog_Skel.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json|二进制文件 (*.skel)|*.skel|文本文件 (*.json)|*.json|所有文件 (*.*)|*.*";
|
||||
openFileDialog_Skel.Multiselect = true;
|
||||
openFileDialog_Skel.Title = "批量选择skel文件";
|
||||
//
|
||||
// SkelFileListBox
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
Controls.Add(tableLayoutPanel1);
|
||||
Name = "SkelFileListBox";
|
||||
Size = new Size(801, 394);
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
flowLayoutPanel1.ResumeLayout(false);
|
||||
flowLayoutPanel1.PerformLayout();
|
||||
contextMenuStrip.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private TableLayoutPanel tableLayoutPanel1;
|
||||
private ListBox listBox;
|
||||
private FlowLayoutPanel flowLayoutPanel1;
|
||||
private Button button_AddFolder;
|
||||
private Button button_AddFile;
|
||||
private FolderBrowserDialog folderBrowserDialog;
|
||||
private Label label_Tip;
|
||||
private ContextMenuStrip contextMenuStrip;
|
||||
private OpenFileDialog openFileDialog_Skel;
|
||||
private ToolStripMenuItem toolStripMenuItem_SelectAll;
|
||||
private ToolStripMenuItem toolStripMenuItem_Paste;
|
||||
private ToolStripMenuItem toolStripMenuItem_Remove;
|
||||
}
|
||||
}
|
||||
123
SpineViewer/Controls/SkelFileListBox.cs
Normal file
123
SpineViewer/Controls/SkelFileListBox.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
|
||||
namespace SpineViewer.Controls
|
||||
{
|
||||
public partial class SkelFileListBox : UserControl
|
||||
{
|
||||
public SkelFileListBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
Items = listBox.Items;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ListBox.Items
|
||||
/// </summary>
|
||||
public readonly ListBox.ObjectCollection Items;
|
||||
|
||||
/// <summary>
|
||||
/// 从路径列表添加
|
||||
/// </summary>
|
||||
private void AddFromFileDrop(string[] paths)
|
||||
{
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
if (Spine.Spine.CommonSkelSuffix.Contains(Path.GetExtension(path).ToLower()))
|
||||
listBox.Items.Add(Path.GetFullPath(path));
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (Spine.Spine.CommonSkelSuffix.Contains(Path.GetExtension(file).ToLower()))
|
||||
listBox.Items.Add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void button_AddFolder_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var path = folderBrowserDialog.SelectedPath;
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (Spine.Spine.CommonSkelSuffix.Contains(Path.GetExtension(file).ToLower()))
|
||||
listBox.Items.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
label_Tip.Text = $"已选择 {listBox.Items.Count} 个文件";
|
||||
}
|
||||
|
||||
private void button_AddFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (openFileDialog_Skel.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
foreach (var p in openFileDialog_Skel.FileNames)
|
||||
listBox.Items.Add(Path.GetFullPath(p));
|
||||
|
||||
label_Tip.Text = $"已选择 {listBox.Items.Count} 个文件";
|
||||
}
|
||||
|
||||
private void listBox_DragEnter(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
else
|
||||
e.Effect = DragDropEffects.None;
|
||||
}
|
||||
|
||||
private void listBox_DragDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
if (!e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
return;
|
||||
|
||||
AddFromFileDrop((string[])e.Data.GetData(DataFormats.FileDrop));
|
||||
label_Tip.Text = $"已选择 {listBox.Items.Count} 个文件";
|
||||
}
|
||||
|
||||
private void toolStripMenuItem_SelectAll_Click(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < listBox.Items.Count; i++)
|
||||
listBox.SelectedIndices.Add(i);
|
||||
}
|
||||
|
||||
private void toolStripMenuItem_Paste_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!Clipboard.ContainsFileDropList())
|
||||
return;
|
||||
|
||||
var fileDropList = Clipboard.GetFileDropList();
|
||||
var paths = new string[fileDropList.Count];
|
||||
fileDropList.CopyTo(paths, 0);
|
||||
AddFromFileDrop(paths);
|
||||
label_Tip.Text = $"已选择 {listBox.Items.Count} 个文件";
|
||||
}
|
||||
|
||||
private void toolStripMenuItem_Remove_Click(object sender, EventArgs e)
|
||||
{
|
||||
var indices = new int[listBox.SelectedIndices.Count];
|
||||
listBox.SelectedIndices.CopyTo(indices, 0);
|
||||
for (int i = indices.Length - 1; i >= 0; i--)
|
||||
listBox.Items.RemoveAt(indices[i]);
|
||||
label_Tip.Text = $"已选择 {listBox.Items.Count} 个文件";
|
||||
}
|
||||
}
|
||||
}
|
||||
129
SpineViewer/Controls/SkelFileListBox.resx
Normal file
129
SpineViewer/Controls/SkelFileListBox.resx
Normal file
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>556, 18</value>
|
||||
</metadata>
|
||||
<metadata name="folderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>286, 21</value>
|
||||
</metadata>
|
||||
<metadata name="openFileDialog_Skel.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>31, 27</value>
|
||||
</metadata>
|
||||
</root>
|
||||
98
SpineViewer/Dialogs/BatchOpenSpineDialog.Designer.cs
generated
98
SpineViewer/Dialogs/BatchOpenSpineDialog.Designer.cs
generated
@@ -37,10 +37,7 @@
|
||||
tableLayoutPanel2 = new TableLayoutPanel();
|
||||
button_Ok = new Button();
|
||||
button_Cancel = new Button();
|
||||
listBox_FilePath = new ListBox();
|
||||
button_SelectSkel = new Button();
|
||||
label_Tip = new Label();
|
||||
openFileDialog_Skel = new OpenFileDialog();
|
||||
skelFileListBox = new SpineViewer.Controls.SkelFileListBox();
|
||||
panel.SuspendLayout();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
tableLayoutPanel2.SuspendLayout();
|
||||
@@ -53,7 +50,7 @@
|
||||
panel.Location = new Point(0, 0);
|
||||
panel.Name = "panel";
|
||||
panel.Padding = new Padding(50, 15, 50, 10);
|
||||
panel.Size = new Size(1126, 449);
|
||||
panel.Size = new Size(1042, 472);
|
||||
panel.TabIndex = 1;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
@@ -62,22 +59,19 @@
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 4);
|
||||
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
|
||||
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 2);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(skelFileListBox, 0, 1);
|
||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new Point(50, 15);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 5;
|
||||
tableLayoutPanel1.RowCount = 3;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.Size = new Size(1026, 424);
|
||||
tableLayoutPanel1.Size = new Size(942, 447);
|
||||
tableLayoutPanel1.TabIndex = 1;
|
||||
//
|
||||
// label4
|
||||
@@ -88,7 +82,7 @@
|
||||
label4.Location = new Point(15, 15);
|
||||
label4.Margin = new Padding(15);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new Size(996, 24);
|
||||
label4.Size = new Size(912, 24);
|
||||
label4.TabIndex = 14;
|
||||
label4.Text = "说明:批量导入只需要选择skel文件,atlas文件需要在同目录下并且与skel文件名相同";
|
||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
||||
@@ -97,7 +91,7 @@
|
||||
//
|
||||
label3.Anchor = AnchorStyles.Right;
|
||||
label3.AutoSize = true;
|
||||
label3.Location = new Point(90, 307);
|
||||
label3.Location = new Point(3, 343);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(50, 24);
|
||||
label3.TabIndex = 12;
|
||||
@@ -108,7 +102,7 @@
|
||||
comboBox_Version.Anchor = AnchorStyles.Left;
|
||||
comboBox_Version.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
comboBox_Version.FormattingEnabled = true;
|
||||
comboBox_Version.Location = new Point(146, 303);
|
||||
comboBox_Version.Location = new Point(59, 339);
|
||||
comboBox_Version.Name = "comboBox_Version";
|
||||
comboBox_Version.Size = new Size(182, 32);
|
||||
comboBox_Version.Sorted = true;
|
||||
@@ -124,18 +118,19 @@
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
||||
tableLayoutPanel2.Location = new Point(3, 381);
|
||||
tableLayoutPanel2.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel2.Location = new Point(3, 404);
|
||||
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
tableLayoutPanel2.RowCount = 1;
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel2.Size = new Size(1020, 40);
|
||||
tableLayoutPanel2.Size = new Size(936, 40);
|
||||
tableLayoutPanel2.TabIndex = 11;
|
||||
//
|
||||
// button_Ok
|
||||
//
|
||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
button_Ok.Location = new Point(368, 3);
|
||||
button_Ok.Location = new Point(326, 3);
|
||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
||||
button_Ok.Name = "button_Ok";
|
||||
button_Ok.Size = new Size(112, 34);
|
||||
@@ -147,7 +142,7 @@
|
||||
// button_Cancel
|
||||
//
|
||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
||||
button_Cancel.Location = new Point(540, 3);
|
||||
button_Cancel.Location = new Point(498, 3);
|
||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
||||
button_Cancel.Name = "button_Cancel";
|
||||
button_Cancel.Size = new Size(112, 34);
|
||||
@@ -156,47 +151,14 @@
|
||||
button_Cancel.UseVisualStyleBackColor = true;
|
||||
button_Cancel.Click += button_Cancel_Click;
|
||||
//
|
||||
// listBox_FilePath
|
||||
// skelFileListBox
|
||||
//
|
||||
tableLayoutPanel1.SetColumnSpan(listBox_FilePath, 2);
|
||||
listBox_FilePath.Dock = DockStyle.Fill;
|
||||
listBox_FilePath.FormattingEnabled = true;
|
||||
listBox_FilePath.HorizontalScrollbar = true;
|
||||
listBox_FilePath.ItemHeight = 24;
|
||||
listBox_FilePath.Location = new Point(3, 97);
|
||||
listBox_FilePath.Name = "listBox_FilePath";
|
||||
listBox_FilePath.Size = new Size(1020, 200);
|
||||
listBox_FilePath.TabIndex = 2;
|
||||
//
|
||||
// button_SelectSkel
|
||||
//
|
||||
button_SelectSkel.Anchor = AnchorStyles.None;
|
||||
button_SelectSkel.Location = new Point(3, 57);
|
||||
button_SelectSkel.Name = "button_SelectSkel";
|
||||
button_SelectSkel.Size = new Size(137, 34);
|
||||
button_SelectSkel.TabIndex = 1;
|
||||
button_SelectSkel.Text = "选择文件...";
|
||||
button_SelectSkel.UseVisualStyleBackColor = true;
|
||||
button_SelectSkel.Click += button_SelectSkel_Click;
|
||||
//
|
||||
// label_Tip
|
||||
//
|
||||
label_Tip.AutoSize = true;
|
||||
label_Tip.Dock = DockStyle.Fill;
|
||||
label_Tip.Location = new Point(146, 54);
|
||||
label_Tip.Name = "label_Tip";
|
||||
label_Tip.Size = new Size(877, 40);
|
||||
label_Tip.TabIndex = 0;
|
||||
label_Tip.Text = "已选择 0 个文件";
|
||||
label_Tip.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// openFileDialog_Skel
|
||||
//
|
||||
openFileDialog_Skel.AddExtension = false;
|
||||
openFileDialog_Skel.AddToRecent = false;
|
||||
openFileDialog_Skel.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json|二进制文件 (*.skel)|*.skel|文本文件 (*.json)|*.json|所有文件 (*.*)|*.*";
|
||||
openFileDialog_Skel.Multiselect = true;
|
||||
openFileDialog_Skel.Title = "批量选择skel文件";
|
||||
tableLayoutPanel1.SetColumnSpan(skelFileListBox, 2);
|
||||
skelFileListBox.Dock = DockStyle.Fill;
|
||||
skelFileListBox.Location = new Point(3, 57);
|
||||
skelFileListBox.Name = "skelFileListBox";
|
||||
skelFileListBox.Size = new Size(936, 276);
|
||||
skelFileListBox.TabIndex = 15;
|
||||
//
|
||||
// BatchOpenSpineDialog
|
||||
//
|
||||
@@ -204,7 +166,7 @@
|
||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
CancelButton = button_Cancel;
|
||||
ClientSize = new Size(1126, 449);
|
||||
ClientSize = new Size(1042, 472);
|
||||
Controls.Add(panel);
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
@@ -214,7 +176,6 @@
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "批量打开骨骼";
|
||||
Load += BatchOpenSpineDialog_Load;
|
||||
panel.ResumeLayout(false);
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
@@ -225,15 +186,12 @@
|
||||
#endregion
|
||||
private Panel panel;
|
||||
private TableLayoutPanel tableLayoutPanel1;
|
||||
private Label label_Tip;
|
||||
private ListBox listBox_FilePath;
|
||||
private Button button_SelectSkel;
|
||||
private TableLayoutPanel tableLayoutPanel2;
|
||||
private Button button_Ok;
|
||||
private Button button_Cancel;
|
||||
private Label label3;
|
||||
private ComboBox comboBox_Version;
|
||||
private OpenFileDialog openFileDialog_Skel;
|
||||
private Label label4;
|
||||
private Controls.SkelFileListBox skelFileListBox;
|
||||
}
|
||||
}
|
||||
@@ -27,33 +27,19 @@ namespace SpineViewer.Dialogs
|
||||
comboBox_Version.SelectedValue = Spine.Version.Auto;
|
||||
}
|
||||
|
||||
private void BatchOpenSpineDialog_Load(object sender, EventArgs e)
|
||||
{
|
||||
button_SelectSkel_Click(sender, e);
|
||||
}
|
||||
|
||||
private void button_SelectSkel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (openFileDialog_Skel.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
listBox_FilePath.Items.Clear();
|
||||
foreach (var p in openFileDialog_Skel.FileNames)
|
||||
listBox_FilePath.Items.Add(Path.GetFullPath(p));
|
||||
label_Tip.Text = $"已选择 {listBox_FilePath.Items.Count} 个文件";
|
||||
}
|
||||
}
|
||||
|
||||
private void button_Ok_Click(object sender, EventArgs e)
|
||||
{
|
||||
var version = (Spine.Version)comboBox_Version.SelectedValue;
|
||||
|
||||
if (listBox_FilePath.Items.Count <= 0)
|
||||
var items = skelFileListBox.Items;
|
||||
|
||||
if (items.Count <= 0)
|
||||
{
|
||||
MessageBox.Info("未选择任何文件");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string p in listBox_FilePath.Items)
|
||||
foreach (string p in items)
|
||||
{
|
||||
if (!File.Exists(p))
|
||||
{
|
||||
@@ -68,7 +54,7 @@ namespace SpineViewer.Dialogs
|
||||
return;
|
||||
}
|
||||
|
||||
Result = new(version, listBox_FilePath.Items.Cast<string>().ToArray());
|
||||
Result = new(version, items.Cast<string>().ToArray());
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,9 +117,6 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="openFileDialog_Skel.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>92, 26</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
171
SpineViewer/Dialogs/ConvertFileFormatDialog.Designer.cs
generated
171
SpineViewer/Dialogs/ConvertFileFormatDialog.Designer.cs
generated
@@ -31,6 +31,7 @@
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConvertFileFormatDialog));
|
||||
panel = new Panel();
|
||||
tableLayoutPanel1 = new TableLayoutPanel();
|
||||
comboBox_TargetVersion = new ComboBox();
|
||||
flowLayoutPanel_TargetFormat = new FlowLayoutPanel();
|
||||
radioButton_BinaryTarget = new RadioButton();
|
||||
radioButton_JsonTarget = new RadioButton();
|
||||
@@ -41,19 +42,13 @@
|
||||
tableLayoutPanel2 = new TableLayoutPanel();
|
||||
button_Ok = new Button();
|
||||
button_Cancel = new Button();
|
||||
listBox_FilePath = new ListBox();
|
||||
button_SelectSkel = new Button();
|
||||
label_Tip = new Label();
|
||||
label2 = new Label();
|
||||
flowLayoutPanel_SourceFormat = new FlowLayoutPanel();
|
||||
radioButton_BinarySource = new RadioButton();
|
||||
radioButton_JsonSource = new RadioButton();
|
||||
skelFileListBox = new SpineViewer.Controls.SkelFileListBox();
|
||||
openFileDialog_Skel = new OpenFileDialog();
|
||||
panel.SuspendLayout();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
flowLayoutPanel_TargetFormat.SuspendLayout();
|
||||
tableLayoutPanel2.SuspendLayout();
|
||||
flowLayoutPanel_SourceFormat.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// panel
|
||||
@@ -63,7 +58,7 @@
|
||||
panel.Location = new Point(0, 0);
|
||||
panel.Name = "panel";
|
||||
panel.Padding = new Padding(50, 15, 50, 10);
|
||||
panel.Size = new Size(1039, 530);
|
||||
panel.Size = new Size(1051, 538);
|
||||
panel.TabIndex = 2;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
@@ -71,40 +66,48 @@
|
||||
tableLayoutPanel1.ColumnCount = 2;
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel_TargetFormat, 1, 5);
|
||||
tableLayoutPanel1.Controls.Add(label1, 0, 4);
|
||||
tableLayoutPanel1.Controls.Add(comboBox_TargetVersion, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel_TargetFormat, 1, 4);
|
||||
tableLayoutPanel1.Controls.Add(label1, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(comboBox_SourceVersion, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 6);
|
||||
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
|
||||
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
|
||||
tableLayoutPanel1.Controls.Add(label2, 0, 5);
|
||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel_SourceFormat, 1, 4);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(comboBox_SourceVersion, 1, 2);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 5);
|
||||
tableLayoutPanel1.Controls.Add(label2, 0, 4);
|
||||
tableLayoutPanel1.Controls.Add(skelFileListBox, 0, 1);
|
||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new Point(50, 15);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 7;
|
||||
tableLayoutPanel1.RowCount = 6;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.Size = new Size(939, 505);
|
||||
tableLayoutPanel1.Size = new Size(951, 513);
|
||||
tableLayoutPanel1.TabIndex = 1;
|
||||
//
|
||||
// comboBox_TargetVersion
|
||||
//
|
||||
comboBox_TargetVersion.Anchor = AnchorStyles.Left;
|
||||
comboBox_TargetVersion.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
comboBox_TargetVersion.FormattingEnabled = true;
|
||||
comboBox_TargetVersion.Location = new Point(95, 365);
|
||||
comboBox_TargetVersion.Name = "comboBox_TargetVersion";
|
||||
comboBox_TargetVersion.Size = new Size(182, 32);
|
||||
comboBox_TargetVersion.Sorted = true;
|
||||
comboBox_TargetVersion.TabIndex = 21;
|
||||
//
|
||||
// flowLayoutPanel_TargetFormat
|
||||
//
|
||||
flowLayoutPanel_TargetFormat.AutoSize = true;
|
||||
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_BinaryTarget);
|
||||
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_JsonTarget);
|
||||
flowLayoutPanel_TargetFormat.Dock = DockStyle.Fill;
|
||||
flowLayoutPanel_TargetFormat.Location = new Point(146, 381);
|
||||
flowLayoutPanel_TargetFormat.Location = new Point(95, 403);
|
||||
flowLayoutPanel_TargetFormat.Name = "flowLayoutPanel_TargetFormat";
|
||||
flowLayoutPanel_TargetFormat.Size = new Size(790, 34);
|
||||
flowLayoutPanel_TargetFormat.Size = new Size(853, 34);
|
||||
flowLayoutPanel_TargetFormat.TabIndex = 19;
|
||||
//
|
||||
// radioButton_BinaryTarget
|
||||
@@ -116,7 +119,6 @@
|
||||
radioButton_BinaryTarget.TabIndex = 17;
|
||||
radioButton_BinaryTarget.Text = "二进制 (*.skel)";
|
||||
radioButton_BinaryTarget.UseVisualStyleBackColor = true;
|
||||
radioButton_BinaryTarget.CheckedChanged += radioButton_Target_CheckedChanged;
|
||||
//
|
||||
// radioButton_JsonTarget
|
||||
//
|
||||
@@ -129,17 +131,16 @@
|
||||
radioButton_JsonTarget.TabStop = true;
|
||||
radioButton_JsonTarget.Text = "文本 (*.json)";
|
||||
radioButton_JsonTarget.UseVisualStyleBackColor = true;
|
||||
radioButton_JsonTarget.CheckedChanged += radioButton_Target_CheckedChanged;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
label1.Anchor = AnchorStyles.Right;
|
||||
label1.AutoSize = true;
|
||||
label1.Location = new Point(72, 346);
|
||||
label1.Location = new Point(3, 369);
|
||||
label1.Name = "label1";
|
||||
label1.Size = new Size(68, 24);
|
||||
label1.Size = new Size(86, 24);
|
||||
label1.TabIndex = 15;
|
||||
label1.Text = "源格式:";
|
||||
label1.Text = "目标版本:";
|
||||
//
|
||||
// label4
|
||||
//
|
||||
@@ -149,7 +150,7 @@
|
||||
label4.Location = new Point(15, 15);
|
||||
label4.Margin = new Padding(15);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new Size(909, 24);
|
||||
label4.Size = new Size(921, 24);
|
||||
label4.TabIndex = 14;
|
||||
label4.Text = "说明:将在每个文件同级目录下生成目标格式后缀的文件,会覆盖已存在文件";
|
||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
||||
@@ -158,19 +159,19 @@
|
||||
//
|
||||
label3.Anchor = AnchorStyles.Right;
|
||||
label3.AutoSize = true;
|
||||
label3.Location = new Point(72, 307);
|
||||
label3.Location = new Point(21, 331);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(68, 24);
|
||||
label3.TabIndex = 12;
|
||||
label3.Text = "源版本:";
|
||||
//
|
||||
// comboBox_Version
|
||||
// comboBox_SourceVersion
|
||||
//
|
||||
comboBox_SourceVersion.Anchor = AnchorStyles.Left;
|
||||
comboBox_SourceVersion.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
comboBox_SourceVersion.FormattingEnabled = true;
|
||||
comboBox_SourceVersion.Location = new Point(146, 303);
|
||||
comboBox_SourceVersion.Name = "comboBox_Version";
|
||||
comboBox_SourceVersion.Location = new Point(95, 327);
|
||||
comboBox_SourceVersion.Name = "comboBox_SourceVersion";
|
||||
comboBox_SourceVersion.Size = new Size(182, 32);
|
||||
comboBox_SourceVersion.Sorted = true;
|
||||
comboBox_SourceVersion.TabIndex = 13;
|
||||
@@ -185,18 +186,19 @@
|
||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
||||
tableLayoutPanel2.Location = new Point(3, 462);
|
||||
tableLayoutPanel2.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel2.Location = new Point(3, 470);
|
||||
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
tableLayoutPanel2.RowCount = 1;
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel2.Size = new Size(933, 40);
|
||||
tableLayoutPanel2.Size = new Size(945, 40);
|
||||
tableLayoutPanel2.TabIndex = 11;
|
||||
//
|
||||
// button_Ok
|
||||
//
|
||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
button_Ok.Location = new Point(324, 3);
|
||||
button_Ok.Location = new Point(330, 3);
|
||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
||||
button_Ok.Name = "button_Ok";
|
||||
button_Ok.Size = new Size(112, 34);
|
||||
@@ -208,7 +210,7 @@
|
||||
// button_Cancel
|
||||
//
|
||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
||||
button_Cancel.Location = new Point(496, 3);
|
||||
button_Cancel.Location = new Point(502, 3);
|
||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
||||
button_Cancel.Name = "button_Cancel";
|
||||
button_Cancel.Size = new Size(112, 34);
|
||||
@@ -217,84 +219,24 @@
|
||||
button_Cancel.UseVisualStyleBackColor = true;
|
||||
button_Cancel.Click += button_Cancel_Click;
|
||||
//
|
||||
// listBox_FilePath
|
||||
//
|
||||
tableLayoutPanel1.SetColumnSpan(listBox_FilePath, 2);
|
||||
listBox_FilePath.Dock = DockStyle.Fill;
|
||||
listBox_FilePath.FormattingEnabled = true;
|
||||
listBox_FilePath.HorizontalScrollbar = true;
|
||||
listBox_FilePath.ItemHeight = 24;
|
||||
listBox_FilePath.Location = new Point(3, 97);
|
||||
listBox_FilePath.Name = "listBox_FilePath";
|
||||
listBox_FilePath.Size = new Size(933, 200);
|
||||
listBox_FilePath.TabIndex = 2;
|
||||
//
|
||||
// button_SelectSkel
|
||||
//
|
||||
button_SelectSkel.Anchor = AnchorStyles.None;
|
||||
button_SelectSkel.Location = new Point(3, 57);
|
||||
button_SelectSkel.Name = "button_SelectSkel";
|
||||
button_SelectSkel.Size = new Size(137, 34);
|
||||
button_SelectSkel.TabIndex = 1;
|
||||
button_SelectSkel.Text = "选择文件...";
|
||||
button_SelectSkel.UseVisualStyleBackColor = true;
|
||||
button_SelectSkel.Click += button_SelectSkel_Click;
|
||||
//
|
||||
// label_Tip
|
||||
//
|
||||
label_Tip.AutoSize = true;
|
||||
label_Tip.Dock = DockStyle.Fill;
|
||||
label_Tip.Location = new Point(146, 54);
|
||||
label_Tip.Name = "label_Tip";
|
||||
label_Tip.Size = new Size(790, 40);
|
||||
label_Tip.TabIndex = 0;
|
||||
label_Tip.Text = "已选择 0 个文件";
|
||||
label_Tip.TextAlign = ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
label2.Anchor = AnchorStyles.Right;
|
||||
label2.AutoSize = true;
|
||||
label2.Location = new Point(54, 386);
|
||||
label2.Location = new Point(3, 408);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new Size(86, 24);
|
||||
label2.TabIndex = 16;
|
||||
label2.Text = "目标格式:";
|
||||
//
|
||||
// flowLayoutPanel_SourceFormat
|
||||
// skelFileListBox
|
||||
//
|
||||
flowLayoutPanel_SourceFormat.AutoSize = true;
|
||||
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_BinarySource);
|
||||
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_JsonSource);
|
||||
flowLayoutPanel_SourceFormat.Dock = DockStyle.Fill;
|
||||
flowLayoutPanel_SourceFormat.Location = new Point(146, 341);
|
||||
flowLayoutPanel_SourceFormat.Name = "flowLayoutPanel_SourceFormat";
|
||||
flowLayoutPanel_SourceFormat.Size = new Size(790, 34);
|
||||
flowLayoutPanel_SourceFormat.TabIndex = 18;
|
||||
//
|
||||
// radioButton_BinarySource
|
||||
//
|
||||
radioButton_BinarySource.AutoSize = true;
|
||||
radioButton_BinarySource.Checked = true;
|
||||
radioButton_BinarySource.Location = new Point(3, 3);
|
||||
radioButton_BinarySource.Name = "radioButton_BinarySource";
|
||||
radioButton_BinarySource.Size = new Size(151, 28);
|
||||
radioButton_BinarySource.TabIndex = 17;
|
||||
radioButton_BinarySource.TabStop = true;
|
||||
radioButton_BinarySource.Text = "二进制 (*.skel)";
|
||||
radioButton_BinarySource.UseVisualStyleBackColor = true;
|
||||
radioButton_BinarySource.CheckedChanged += radioButton_Source_CheckedChanged;
|
||||
//
|
||||
// radioButton_JsonSource
|
||||
//
|
||||
radioButton_JsonSource.AutoSize = true;
|
||||
radioButton_JsonSource.Location = new Point(160, 3);
|
||||
radioButton_JsonSource.Name = "radioButton_JsonSource";
|
||||
radioButton_JsonSource.Size = new Size(135, 28);
|
||||
radioButton_JsonSource.TabIndex = 18;
|
||||
radioButton_JsonSource.Text = "文本 (*.json)";
|
||||
radioButton_JsonSource.UseVisualStyleBackColor = true;
|
||||
radioButton_JsonSource.CheckedChanged += radioButton_Source_CheckedChanged;
|
||||
tableLayoutPanel1.SetColumnSpan(skelFileListBox, 2);
|
||||
skelFileListBox.Dock = DockStyle.Fill;
|
||||
skelFileListBox.Location = new Point(3, 57);
|
||||
skelFileListBox.Name = "skelFileListBox";
|
||||
skelFileListBox.Size = new Size(945, 264);
|
||||
skelFileListBox.TabIndex = 20;
|
||||
//
|
||||
// openFileDialog_Skel
|
||||
//
|
||||
@@ -310,7 +252,7 @@
|
||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
CancelButton = button_Cancel;
|
||||
ClientSize = new Size(1039, 530);
|
||||
ClientSize = new Size(1051, 538);
|
||||
Controls.Add(panel);
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
@@ -320,15 +262,12 @@
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "骨骼文件格式转换";
|
||||
Load += ConvertFileFormatDialog_Load;
|
||||
panel.ResumeLayout(false);
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
flowLayoutPanel_TargetFormat.ResumeLayout(false);
|
||||
flowLayoutPanel_TargetFormat.PerformLayout();
|
||||
tableLayoutPanel2.ResumeLayout(false);
|
||||
flowLayoutPanel_SourceFormat.ResumeLayout(false);
|
||||
flowLayoutPanel_SourceFormat.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
@@ -342,17 +281,13 @@
|
||||
private TableLayoutPanel tableLayoutPanel2;
|
||||
private Button button_Ok;
|
||||
private Button button_Cancel;
|
||||
private ListBox listBox_FilePath;
|
||||
private Button button_SelectSkel;
|
||||
private Label label_Tip;
|
||||
private OpenFileDialog openFileDialog_Skel;
|
||||
private Label label1;
|
||||
private Label label2;
|
||||
private RadioButton radioButton_BinarySource;
|
||||
private FlowLayoutPanel flowLayoutPanel_SourceFormat;
|
||||
private RadioButton radioButton_JsonSource;
|
||||
private FlowLayoutPanel flowLayoutPanel_TargetFormat;
|
||||
private RadioButton radioButton_BinaryTarget;
|
||||
private RadioButton radioButton_JsonTarget;
|
||||
private Controls.SkelFileListBox skelFileListBox;
|
||||
private ComboBox comboBox_TargetVersion;
|
||||
}
|
||||
}
|
||||
@@ -13,62 +13,44 @@ namespace SpineViewer.Dialogs
|
||||
{
|
||||
public partial class ConvertFileFormatDialog : Form
|
||||
{
|
||||
// TODO: 增加版本转换选项
|
||||
// TODO: 使用结果包装类
|
||||
public string[] SkelPaths { get; private set; }
|
||||
public Spine.Version SourceVersion { get; private set; }
|
||||
public Spine.Version TargetVersion { get; private set; }
|
||||
public bool JsonSource { get; private set; }
|
||||
public bool JsonTarget { get; private set; }
|
||||
/// <summary>
|
||||
/// 对话框结果, 取消时为 null
|
||||
/// </summary>
|
||||
public ConvertFileFormatDialogResult Result { get; private set; }
|
||||
|
||||
public ConvertFileFormatDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// XXX: 文件格式转换暂时不支持自动检测版本
|
||||
var impVersions = VersionHelper.Names.ToDictionary();
|
||||
impVersions.Remove(Spine.Version.Auto);
|
||||
|
||||
comboBox_SourceVersion.DataSource = impVersions.ToList();
|
||||
comboBox_SourceVersion.DataSource = VersionHelper.Names.ToList();
|
||||
comboBox_SourceVersion.DisplayMember = "Value";
|
||||
comboBox_SourceVersion.ValueMember = "Key";
|
||||
comboBox_SourceVersion.SelectedValue = Spine.Version.V38;
|
||||
//comboBox_TargetVersion.DataSource = VersionHelper.Versions.ToList();
|
||||
//comboBox_TargetVersion.DisplayMember = "Value";
|
||||
//comboBox_TargetVersion.ValueMember = "Key";
|
||||
//comboBox_TargetVersion.SelectedValue = Spine.Version.V38;
|
||||
}
|
||||
comboBox_SourceVersion.SelectedValue = Spine.Version.Auto;
|
||||
|
||||
private void ConvertFileFormatDialog_Load(object sender, EventArgs e)
|
||||
{
|
||||
button_SelectSkel_Click(sender, e);
|
||||
}
|
||||
|
||||
private void button_SelectSkel_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (openFileDialog_Skel.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
listBox_FilePath.Items.Clear();
|
||||
foreach (var p in openFileDialog_Skel.FileNames)
|
||||
listBox_FilePath.Items.Add(Path.GetFullPath(p));
|
||||
label_Tip.Text = $"已选择 {listBox_FilePath.Items.Count} 个文件";
|
||||
}
|
||||
// 目标版本不包含自动
|
||||
var versionsWithoutAuto = VersionHelper.Names.ToDictionary();
|
||||
versionsWithoutAuto.Remove(Spine.Version.Auto);
|
||||
comboBox_TargetVersion.DataSource = versionsWithoutAuto.ToList();
|
||||
comboBox_TargetVersion.DisplayMember = "Value";
|
||||
comboBox_TargetVersion.ValueMember = "Key";
|
||||
comboBox_TargetVersion.SelectedValue = Spine.Version.V38;
|
||||
}
|
||||
|
||||
private void button_Ok_Click(object sender, EventArgs e)
|
||||
{
|
||||
var sourceVersion = (Spine.Version)comboBox_SourceVersion.SelectedValue;
|
||||
var targetVersion = (Spine.Version)comboBox_SourceVersion.SelectedValue; // TODO: 增加目标版本
|
||||
var jsonSource = radioButton_JsonSource.Checked;
|
||||
var targetVersion = (Spine.Version)comboBox_TargetVersion.SelectedValue;
|
||||
var jsonTarget = radioButton_JsonTarget.Checked;
|
||||
|
||||
if (listBox_FilePath.Items.Count <= 0)
|
||||
var items = skelFileListBox.Items;
|
||||
|
||||
if (items.Count <= 0)
|
||||
{
|
||||
MessageBox.Info("未选择任何文件");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string p in listBox_FilePath.Items)
|
||||
foreach (string p in items)
|
||||
{
|
||||
if (!File.Exists(p))
|
||||
{
|
||||
@@ -77,7 +59,7 @@ namespace SpineViewer.Dialogs
|
||||
}
|
||||
}
|
||||
|
||||
if (!SkeletonConverter.ImplementedVersions.Contains(sourceVersion))
|
||||
if (sourceVersion != Spine.Version.Auto && !SkeletonConverter.ImplementedVersions.Contains(sourceVersion))
|
||||
{
|
||||
MessageBox.Info($"{sourceVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
||||
return;
|
||||
@@ -89,18 +71,7 @@ namespace SpineViewer.Dialogs
|
||||
return;
|
||||
}
|
||||
|
||||
if (jsonSource == jsonTarget && sourceVersion == targetVersion)
|
||||
{
|
||||
MessageBox.Info($"不需要转换相同的格式和版本");
|
||||
return;
|
||||
}
|
||||
|
||||
SkelPaths = listBox_FilePath.Items.Cast<string>().ToArray();
|
||||
SourceVersion = sourceVersion;
|
||||
TargetVersion = targetVersion;
|
||||
JsonSource = jsonSource;
|
||||
JsonTarget = jsonTarget;
|
||||
|
||||
Result = new(items.Cast<string>().ToArray(), sourceVersion, targetVersion, jsonTarget);
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
@@ -108,21 +79,31 @@ namespace SpineViewer.Dialogs
|
||||
{
|
||||
DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
}
|
||||
|
||||
private void radioButton_Source_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (radioButton_BinarySource.Checked)
|
||||
radioButton_JsonTarget.Checked = true;
|
||||
else
|
||||
radioButton_BinaryTarget.Checked = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 文件格式转换对话框结果包装类
|
||||
/// </summary>
|
||||
public class ConvertFileFormatDialogResult(string[] skelPaths, Spine.Version sourceVersion, Spine.Version targetVersion, bool jsonTarget)
|
||||
{
|
||||
/// <summary>
|
||||
/// 骨骼文件路径列表
|
||||
/// </summary>
|
||||
public string[] SkelPaths => skelPaths;
|
||||
|
||||
private void radioButton_Target_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (radioButton_BinaryTarget.Checked)
|
||||
radioButton_JsonSource.Checked = true;
|
||||
else
|
||||
radioButton_BinarySource.Checked = true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 源版本
|
||||
/// </summary>
|
||||
public Spine.Version SourceVersion => sourceVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 目标版本
|
||||
/// </summary>
|
||||
public Spine.Version TargetVersion => targetVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 目标格式是否为 Json
|
||||
/// </summary>
|
||||
public bool JsonTarget => jsonTarget;
|
||||
}
|
||||
}
|
||||
|
||||
105
SpineViewer/Dialogs/ExportPreviewDialog.Designer.cs
generated
105
SpineViewer/Dialogs/ExportPreviewDialog.Designer.cs
generated
@@ -31,23 +31,18 @@
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportPreviewDialog));
|
||||
panel1 = new Panel();
|
||||
tableLayoutPanel1 = new TableLayoutPanel();
|
||||
propertyGrid = new PropertyGrid();
|
||||
label4 = new Label();
|
||||
label1 = new Label();
|
||||
label2 = new Label();
|
||||
label3 = new Label();
|
||||
textBox_OutputDir = new TextBox();
|
||||
button_SelectOutputDir = new Button();
|
||||
tableLayoutPanel2 = new TableLayoutPanel();
|
||||
button_Ok = new Button();
|
||||
button_Cancel = new Button();
|
||||
numericUpDown_Width = new NumericUpDown();
|
||||
numericUpDown_Height = new NumericUpDown();
|
||||
folderBrowserDialog = new FolderBrowserDialog();
|
||||
panel1.SuspendLayout();
|
||||
tableLayoutPanel1.SuspendLayout();
|
||||
tableLayoutPanel2.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Width).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Height).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// panel1
|
||||
@@ -57,7 +52,7 @@
|
||||
panel1.Location = new Point(0, 0);
|
||||
panel1.Name = "panel1";
|
||||
panel1.Padding = new Padding(50, 15, 50, 10);
|
||||
panel1.Size = new Size(919, 276);
|
||||
panel1.Size = new Size(914, 482);
|
||||
panel1.TabIndex = 2;
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
@@ -68,27 +63,34 @@
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
||||
tableLayoutPanel1.Controls.Add(propertyGrid, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
||||
tableLayoutPanel1.Controls.Add(label1, 0, 1);
|
||||
tableLayoutPanel1.Controls.Add(label2, 0, 2);
|
||||
tableLayoutPanel1.Controls.Add(label3, 0, 3);
|
||||
tableLayoutPanel1.Controls.Add(textBox_OutputDir, 1, 1);
|
||||
tableLayoutPanel1.Controls.Add(button_SelectOutputDir, 3, 1);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 4);
|
||||
tableLayoutPanel1.Controls.Add(numericUpDown_Width, 1, 2);
|
||||
tableLayoutPanel1.Controls.Add(numericUpDown_Height, 1, 3);
|
||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 3);
|
||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||
tableLayoutPanel1.Location = new Point(50, 15);
|
||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
tableLayoutPanel1.RowCount = 5;
|
||||
tableLayoutPanel1.RowCount = 4;
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel1.Size = new Size(819, 251);
|
||||
tableLayoutPanel1.Size = new Size(814, 457);
|
||||
tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// propertyGrid
|
||||
//
|
||||
tableLayoutPanel1.SetColumnSpan(propertyGrid, 4);
|
||||
propertyGrid.Dock = DockStyle.Fill;
|
||||
propertyGrid.HelpVisible = false;
|
||||
propertyGrid.Location = new Point(3, 97);
|
||||
propertyGrid.Name = "propertyGrid";
|
||||
propertyGrid.Size = new Size(808, 284);
|
||||
propertyGrid.TabIndex = 1;
|
||||
propertyGrid.ToolbarVisible = false;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
label4.AutoSize = true;
|
||||
@@ -97,9 +99,9 @@
|
||||
label4.Location = new Point(15, 15);
|
||||
label4.Margin = new Padding(15);
|
||||
label4.Name = "label4";
|
||||
label4.Size = new Size(789, 24);
|
||||
label4.Size = new Size(784, 24);
|
||||
label4.TabIndex = 11;
|
||||
label4.Text = "说明:导出的文件名与骨骼文件名相同";
|
||||
label4.Text = "说明:输出文件夹为可选项,留空则将预览图输出到每个骨骼文件所在目录";
|
||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label1
|
||||
@@ -112,40 +114,20 @@
|
||||
label1.TabIndex = 0;
|
||||
label1.Text = "输出文件夹:";
|
||||
//
|
||||
// label2
|
||||
//
|
||||
label2.Anchor = AnchorStyles.Right;
|
||||
label2.AutoSize = true;
|
||||
label2.Location = new Point(75, 100);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new Size(32, 24);
|
||||
label2.TabIndex = 1;
|
||||
label2.Text = "宽:";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
label3.Anchor = AnchorStyles.Right;
|
||||
label3.AutoSize = true;
|
||||
label3.Location = new Point(75, 136);
|
||||
label3.Name = "label3";
|
||||
label3.Size = new Size(32, 24);
|
||||
label3.TabIndex = 2;
|
||||
label3.Text = "高:";
|
||||
//
|
||||
// textBox_OutputDir
|
||||
//
|
||||
tableLayoutPanel1.SetColumnSpan(textBox_OutputDir, 2);
|
||||
textBox_OutputDir.Dock = DockStyle.Fill;
|
||||
textBox_OutputDir.Location = new Point(113, 57);
|
||||
textBox_OutputDir.Name = "textBox_OutputDir";
|
||||
textBox_OutputDir.Size = new Size(664, 30);
|
||||
textBox_OutputDir.Size = new Size(660, 30);
|
||||
textBox_OutputDir.TabIndex = 3;
|
||||
//
|
||||
// button_SelectOutputDir
|
||||
//
|
||||
button_SelectOutputDir.AutoSize = true;
|
||||
button_SelectOutputDir.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||
button_SelectOutputDir.Location = new Point(783, 57);
|
||||
button_SelectOutputDir.Location = new Point(779, 57);
|
||||
button_SelectOutputDir.Name = "button_SelectOutputDir";
|
||||
button_SelectOutputDir.Size = new Size(32, 34);
|
||||
button_SelectOutputDir.TabIndex = 5;
|
||||
@@ -164,17 +146,18 @@
|
||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
||||
tableLayoutPanel2.Location = new Point(3, 208);
|
||||
tableLayoutPanel2.Location = new Point(3, 414);
|
||||
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
tableLayoutPanel2.RowCount = 1;
|
||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||
tableLayoutPanel2.Size = new Size(813, 40);
|
||||
tableLayoutPanel2.Size = new Size(808, 40);
|
||||
tableLayoutPanel2.TabIndex = 10;
|
||||
//
|
||||
// button_Ok
|
||||
//
|
||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||
button_Ok.Location = new Point(264, 3);
|
||||
button_Ok.Location = new Point(262, 3);
|
||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
||||
button_Ok.Name = "button_Ok";
|
||||
button_Ok.Size = new Size(112, 34);
|
||||
@@ -186,7 +169,7 @@
|
||||
// button_Cancel
|
||||
//
|
||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
||||
button_Cancel.Location = new Point(436, 3);
|
||||
button_Cancel.Location = new Point(434, 3);
|
||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
||||
button_Cancel.Name = "button_Cancel";
|
||||
button_Cancel.Size = new Size(112, 34);
|
||||
@@ -195,30 +178,6 @@
|
||||
button_Cancel.UseVisualStyleBackColor = true;
|
||||
button_Cancel.Click += button_Cancel_Click;
|
||||
//
|
||||
// numericUpDown_Width
|
||||
//
|
||||
numericUpDown_Width.Anchor = AnchorStyles.Left;
|
||||
numericUpDown_Width.Location = new Point(113, 97);
|
||||
numericUpDown_Width.Maximum = new decimal(new int[] { 4096, 0, 0, 0 });
|
||||
numericUpDown_Width.Minimum = new decimal(new int[] { 32, 0, 0, 0 });
|
||||
numericUpDown_Width.Name = "numericUpDown_Width";
|
||||
numericUpDown_Width.Size = new Size(180, 30);
|
||||
numericUpDown_Width.TabIndex = 12;
|
||||
numericUpDown_Width.TextAlign = HorizontalAlignment.Right;
|
||||
numericUpDown_Width.Value = new decimal(new int[] { 256, 0, 0, 0 });
|
||||
//
|
||||
// numericUpDown_Height
|
||||
//
|
||||
numericUpDown_Height.Anchor = AnchorStyles.Left;
|
||||
numericUpDown_Height.Location = new Point(113, 133);
|
||||
numericUpDown_Height.Maximum = new decimal(new int[] { 4096, 0, 0, 0 });
|
||||
numericUpDown_Height.Minimum = new decimal(new int[] { 32, 0, 0, 0 });
|
||||
numericUpDown_Height.Name = "numericUpDown_Height";
|
||||
numericUpDown_Height.Size = new Size(180, 30);
|
||||
numericUpDown_Height.TabIndex = 13;
|
||||
numericUpDown_Height.TextAlign = HorizontalAlignment.Right;
|
||||
numericUpDown_Height.Value = new decimal(new int[] { 256, 0, 0, 0 });
|
||||
//
|
||||
// folderBrowserDialog
|
||||
//
|
||||
folderBrowserDialog.AddToRecent = false;
|
||||
@@ -229,7 +188,7 @@
|
||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
CancelButton = button_Cancel;
|
||||
ClientSize = new Size(919, 276);
|
||||
ClientSize = new Size(914, 482);
|
||||
Controls.Add(panel1);
|
||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||
@@ -239,14 +198,11 @@
|
||||
ShowInTaskbar = false;
|
||||
StartPosition = FormStartPosition.CenterScreen;
|
||||
Text = "导出预览图";
|
||||
Load += ExportPreviewDialog_Load;
|
||||
panel1.ResumeLayout(false);
|
||||
panel1.PerformLayout();
|
||||
tableLayoutPanel1.ResumeLayout(false);
|
||||
tableLayoutPanel1.PerformLayout();
|
||||
tableLayoutPanel2.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Width).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Height).EndInit();
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
@@ -256,15 +212,12 @@
|
||||
private TableLayoutPanel tableLayoutPanel1;
|
||||
private Label label4;
|
||||
private Label label1;
|
||||
private Label label2;
|
||||
private Label label3;
|
||||
private TextBox textBox_OutputDir;
|
||||
private Button button_SelectOutputDir;
|
||||
private TableLayoutPanel tableLayoutPanel2;
|
||||
private Button button_Ok;
|
||||
private Button button_Cancel;
|
||||
private NumericUpDown numericUpDown_Width;
|
||||
private NumericUpDown numericUpDown_Height;
|
||||
private FolderBrowserDialog folderBrowserDialog;
|
||||
private PropertyGrid propertyGrid;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -12,60 +13,66 @@ namespace SpineViewer.Dialogs
|
||||
{
|
||||
public partial class ExportPreviewDialog: Form
|
||||
{
|
||||
// TODO: 用单独的结果包装类
|
||||
public string OutputDir { get; private set; }
|
||||
public uint PreviewWidth { get; private set; }
|
||||
public uint PreviewHeight { get; private set; }
|
||||
/// <summary>
|
||||
/// 对话框结果
|
||||
/// </summary>
|
||||
public readonly ExportPreviewDialogResult Result = new();
|
||||
|
||||
public ExportPreviewDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void ExportPreviewDialog_Load(object sender, EventArgs e)
|
||||
{
|
||||
button_SelectOutputDir_Click(sender, e);
|
||||
propertyGrid.SelectedObject = Result;
|
||||
}
|
||||
|
||||
private void button_SelectOutputDir_Click(object sender, EventArgs e)
|
||||
{
|
||||
folderBrowserDialog.InitialDirectory = textBox_OutputDir.Text;
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
textBox_OutputDir.Text = Path.GetFullPath(folderBrowserDialog.SelectedPath);
|
||||
}
|
||||
if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
textBox_OutputDir.Text = Path.GetFullPath(folderBrowserDialog.SelectedPath);
|
||||
}
|
||||
|
||||
private void button_Ok_Click(object sender, EventArgs e)
|
||||
{
|
||||
var outputDir = textBox_OutputDir.Text;
|
||||
if (File.Exists(outputDir))
|
||||
if (string.IsNullOrEmpty(outputDir))
|
||||
{
|
||||
MessageBox.Info("输出文件夹无效");
|
||||
outputDir = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (File.Exists(outputDir))
|
||||
{
|
||||
MessageBox.Info("输出文件夹无效");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(outputDir))
|
||||
{
|
||||
if (MessageBox.Quest($"文件夹 {outputDir} 不存在,是否创建?") != DialogResult.OK)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error(ex.ToString());
|
||||
MessageBox.Error(ex.ToString(), "文件夹创建失败");
|
||||
return;
|
||||
}
|
||||
}
|
||||
outputDir = Path.GetFullPath(outputDir);
|
||||
}
|
||||
|
||||
if (outputDir is null && string.IsNullOrEmpty(Result.NameSuffix))
|
||||
{
|
||||
MessageBox.Info("输出文件夹和名称后缀不可同时为空,存在文件覆盖风险");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(outputDir))
|
||||
{
|
||||
if (MessageBox.Quest($"文件夹 {outputDir} 不存在,是否创建?") != DialogResult.OK)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Program.Logger.Error(ex.ToString());
|
||||
MessageBox.Error(ex.ToString(), "文件夹创建失败");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
OutputDir = Path.GetFullPath(outputDir);
|
||||
PreviewWidth = (uint)numericUpDown_Width.Value;
|
||||
PreviewHeight = (uint)numericUpDown_Height.Value;
|
||||
|
||||
Result.OutputDir = outputDir;
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
@@ -74,4 +81,89 @@ namespace SpineViewer.Dialogs
|
||||
DialogResult = DialogResult.Cancel;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExportPreviewDialogResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 输出路径
|
||||
/// </summary>
|
||||
[Browsable(false)]
|
||||
public string? OutputDir { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 预览图格式
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(ImageFormatConverter))]
|
||||
[Category("图像"), DisplayName("预览图格式")]
|
||||
public ImageFormat ImageFormat
|
||||
{
|
||||
get => imageFormat;
|
||||
set
|
||||
{
|
||||
if (value == ImageFormat.MemoryBmp) value = ImageFormat.Bmp;
|
||||
imageFormat = value;
|
||||
}
|
||||
}
|
||||
private ImageFormat imageFormat = ImageFormat.Png;
|
||||
|
||||
/// <summary>
|
||||
/// 预览图分辨率
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SizeConverter))]
|
||||
[Category("图像"), DisplayName("分辨率")]
|
||||
public Size Resolution
|
||||
{
|
||||
get => resolution;
|
||||
set
|
||||
{
|
||||
if (value.Width <= 0) value.Width = 128;
|
||||
if (value.Height <= 0) value.Height = 128;
|
||||
resolution = value;
|
||||
}
|
||||
}
|
||||
private Size resolution = new(512, 512);
|
||||
|
||||
/// <summary>
|
||||
/// 四周填充像素值
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(PaddingConverter))]
|
||||
[Category("图像"), DisplayName("四周填充像素值")]
|
||||
public Padding Padding
|
||||
{
|
||||
get => padding;
|
||||
set
|
||||
{
|
||||
if (value.Left <= 0) value.Left = 10;
|
||||
if (value.Right <= 0) value.Right = 10;
|
||||
if (value.Top <= 0) value.Top = 10;
|
||||
if (value.Bottom <= 0) value.Bottom = 10;
|
||||
padding = value;
|
||||
}
|
||||
}
|
||||
private Padding padding = new(1);
|
||||
|
||||
/// <summary>
|
||||
/// DPI
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(SizeFConverter))]
|
||||
[Category("图像"), DisplayName("DPI")]
|
||||
public SizeF DPI
|
||||
{
|
||||
get => dpi;
|
||||
set
|
||||
{
|
||||
if (value.Width <= 0) value.Width = 144;
|
||||
if (value.Height <= 0) value.Height = 144;
|
||||
dpi = value;
|
||||
}
|
||||
}
|
||||
private SizeF dpi = new(144, 144);
|
||||
|
||||
/// <summary>
|
||||
/// 名称后缀
|
||||
/// </summary>
|
||||
[Category("其他"), DisplayName("名称后缀")]
|
||||
public string NameSuffix { get; set; } = "(preview)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
64
SpineViewer/ExportHelper.cs
Normal file
64
SpineViewer/ExportHelper.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using FFMpegCore.Pipes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
|
||||
|
||||
namespace SpineViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// SFML.Graphics.Image 帧对象包装类
|
||||
/// </summary>
|
||||
public class SFMLImageVideoFrame(SFML.Graphics.Image image) : IVideoFrame, IDisposable
|
||||
{
|
||||
public int Width => (int)image.Size.X;
|
||||
public int Height => (int)image.Size.Y;
|
||||
public string Format => "rgba";
|
||||
public void Serialize(Stream pipe) => pipe.Write(image.Pixels);
|
||||
public async Task SerializeAsync(Stream pipe, CancellationToken token) => await pipe.WriteAsync(image.Pixels, token);
|
||||
public void Dispose() => image.Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Save the contents of the image to a file
|
||||
/// </summary>
|
||||
/// <param name="filename">Path of the file to save (overwritten if already exist)</param>
|
||||
/// <returns>True if saving was successful</returns>
|
||||
public bool SaveToFile(string filename) => image.SaveToFile(filename);
|
||||
|
||||
/// <summary>
|
||||
/// Save the image to a buffer in memory The format of the image must be specified.
|
||||
/// The supported image formats are bmp, png, tga and jpg. This function fails if
|
||||
/// the image is empty, or if the format was invalid.
|
||||
/// </summary>
|
||||
/// <param name="output">Byte array filled with encoded data</param>
|
||||
/// <param name="format">Encoding format to use</param>
|
||||
/// <returns>True if saving was successful</returns>
|
||||
public bool SaveToMemory(out byte[] output, string format) => image.SaveToMemory(out output, format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为帧导出创建的辅助类
|
||||
/// </summary>
|
||||
public static class ExportHelper
|
||||
{
|
||||
public static Bitmap CopyToBitmap(this SFML.Graphics.Texture tex)
|
||||
{
|
||||
using var img = tex.CopyToImage();
|
||||
img.SaveToMemory(out var imgBuffer, "bmp");
|
||||
using var stream = new MemoryStream(imgBuffer);
|
||||
return new Bitmap(stream);
|
||||
}
|
||||
|
||||
public static SFMLImageVideoFrame CopyToFrame(this SFML.Graphics.Texture tex) => new(tex.CopyToImage());
|
||||
|
||||
public static string GetSuffix(this ImageFormat imageFormat)
|
||||
{
|
||||
if (imageFormat == ImageFormat.Icon) return ".ico";
|
||||
else if (imageFormat == ImageFormat.Exif) return ".jpg";
|
||||
else return $".{imageFormat.ToString().ToLower()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace SpineViewer
|
||||
|
||||
var progressDialog = new Dialogs.ProgressDialog();
|
||||
progressDialog.DoWork += ExportPreview_Work;
|
||||
progressDialog.RunWorkerAsync(saveDialog);
|
||||
progressDialog.RunWorkerAsync(saveDialog.Result);
|
||||
progressDialog.ShowDialog();
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace SpineViewer
|
||||
|
||||
var progressDialog = new Dialogs.ProgressDialog();
|
||||
progressDialog.DoWork += ConvertFileFormat_Work;
|
||||
progressDialog.RunWorkerAsync(openDialog);
|
||||
progressDialog.RunWorkerAsync(openDialog.Result);
|
||||
progressDialog.ShowDialog();
|
||||
}
|
||||
|
||||
@@ -294,17 +294,17 @@ namespace SpineViewer
|
||||
private void ExportPreview_Work(object? sender, DoWorkEventArgs e)
|
||||
{
|
||||
var worker = sender as BackgroundWorker;
|
||||
var arguments = e.Argument as Dialogs.ExportPreviewDialog;
|
||||
var outputDir = arguments.OutputDir;
|
||||
var width = arguments.PreviewWidth;
|
||||
var height = arguments.PreviewHeight;
|
||||
// TODO: 增加填充参数
|
||||
var paddingL = 1u;
|
||||
var paddingR = 1u;
|
||||
var paddingT = 1u;
|
||||
var paddingB = 1u;
|
||||
var arguments = e.Argument as Dialogs.ExportPreviewDialogResult;
|
||||
|
||||
var tex = new SFML.Graphics.RenderTexture(width, height);
|
||||
var outputDir = arguments.OutputDir;
|
||||
var imageFormat = arguments.ImageFormat;
|
||||
var resolution = arguments.Resolution;
|
||||
var padding = arguments.Padding;
|
||||
var dpi = arguments.DPI;
|
||||
var nameSuffix = arguments.NameSuffix;
|
||||
var renderSelectedOnly = spinePreviewer.RenderSelectedOnly;
|
||||
|
||||
var tex = new SFML.Graphics.RenderTexture((uint)resolution.Width, (uint)resolution.Height);
|
||||
|
||||
int success = 0;
|
||||
int error = 0;
|
||||
@@ -323,18 +323,26 @@ namespace SpineViewer
|
||||
}
|
||||
|
||||
var spine = spines[i];
|
||||
if (renderSelectedOnly && !spine.IsSelected)
|
||||
continue;
|
||||
|
||||
var filename = $"{spine.Name}{nameSuffix}{imageFormat.GetSuffix()}";
|
||||
var savePath = outputDir is null ? Path.Combine(spine.AssetsDir, filename) : Path.Combine(outputDir, filename);
|
||||
|
||||
var tmp = spine.CurrentAnimation;
|
||||
spine.CurrentAnimation = Spine.Spine.EMPTY_ANIMATION;
|
||||
tex.SetView(spine.GetInitView(width, height, paddingL, paddingR, paddingT, paddingB));
|
||||
tex.SetView(spine.GetInitView(resolution, padding));
|
||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||
tex.Draw(spine);
|
||||
tex.Display();
|
||||
spine.CurrentAnimation = tmp;
|
||||
|
||||
try
|
||||
{
|
||||
using (var img = tex.Texture.CopyToImage())
|
||||
using (var img = new Bitmap(tex.Texture.CopyToBitmap()))
|
||||
{
|
||||
img.SaveToFile(Path.Combine(outputDir, $"{spine.Name}.png"));
|
||||
img.SetResolution(dpi.Width, dpi.Height);
|
||||
img.Save(savePath, imageFormat);
|
||||
}
|
||||
success++;
|
||||
}
|
||||
@@ -365,28 +373,19 @@ namespace SpineViewer
|
||||
private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e)
|
||||
{
|
||||
var worker = sender as BackgroundWorker;
|
||||
var arguments = e.Argument as Dialogs.ConvertFileFormatDialog;
|
||||
var arguments = e.Argument as Dialogs.ConvertFileFormatDialogResult;
|
||||
var skelPaths = arguments.SkelPaths;
|
||||
var srcVersion = arguments.SourceVersion;
|
||||
var tgtVersion = arguments.TargetVersion;
|
||||
var jsonSource = arguments.JsonSource;
|
||||
var jsonTarget = arguments.JsonTarget;
|
||||
var newSuffix = jsonTarget ? ".json" : ".skel";
|
||||
|
||||
if (jsonTarget == jsonSource)
|
||||
{
|
||||
if (tgtVersion == srcVersion)
|
||||
return;
|
||||
else
|
||||
newSuffix += $".{tgtVersion.ToString().ToLower()}"; // TODO: 仅转换版本的情况下考虑文件覆盖问题
|
||||
}
|
||||
|
||||
int totalCount = skelPaths.Length;
|
||||
int success = 0;
|
||||
int error = 0;
|
||||
|
||||
SkeletonConverter srcCvter = SkeletonConverter.New(srcVersion);
|
||||
SkeletonConverter tgtCvter = tgtVersion == srcVersion ? srcCvter : SkeletonConverter.New(tgtVersion);
|
||||
SkeletonConverter srcCvter = srcVersion != Spine.Version.Auto ? SkeletonConverter.New(srcVersion) : null;
|
||||
SkeletonConverter tgtCvter = SkeletonConverter.New(tgtVersion);
|
||||
|
||||
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
@@ -402,8 +401,15 @@ namespace SpineViewer
|
||||
|
||||
try
|
||||
{
|
||||
var root = jsonSource ? srcCvter.ReadJson(skelPath) : srcCvter.ReadBinary(skelPath);
|
||||
if (tgtVersion != srcVersion) root = srcCvter.ToVersion(root, tgtVersion);
|
||||
if (srcVersion == Spine.Version.Auto)
|
||||
{
|
||||
if (Spine.Spine.GetVersion(skelPath) is Spine.Version detectedSrcVersion)
|
||||
srcCvter = SkeletonConverter.New(detectedSrcVersion);
|
||||
else
|
||||
throw new InvalidDataException($"Auto version detection failed for {skelPath}, try to use a specific version");
|
||||
}
|
||||
var root = srcCvter.Read(skelPath);
|
||||
root = srcCvter.ToVersion(root, tgtVersion);
|
||||
if (jsonTarget) tgtCvter.WriteJson(root, newPath); else tgtCvter.WriteBinary(root, newPath);
|
||||
success++;
|
||||
}
|
||||
|
||||
@@ -111,6 +111,29 @@ namespace SpineViewer.Spine
|
||||
root.WriteTo(writer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取骨骼文件
|
||||
/// </summary>
|
||||
public JsonObject Read(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReadBinary(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReadJson(path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 都不行就报错
|
||||
throw new InvalidDataException($"Unknown skeleton file format {path}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换到目标版本
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<Version>0.10.7</Version>
|
||||
<Version>0.10.9</Version>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>appicon.ico</ApplicationIcon>
|
||||
|
||||
Reference in New Issue
Block a user