Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1b0d0a2ad | ||
|
|
2c050ba031 | ||
|
|
41518b16b4 | ||
|
|
72a16dc95f | ||
|
|
3404c64f55 | ||
|
|
b9015422f8 | ||
|
|
a7441b968d | ||
|
|
2d44be31f7 | ||
|
|
c2cf25bb2b | ||
|
|
7c4c53dcb0 | ||
|
|
aceb3b17c8 | ||
|
|
adfcfdb1de | ||
|
|
da329723bc | ||
|
|
63eb53fa06 | ||
|
|
d32c824515 | ||
|
|
e9ee8c481c | ||
|
|
6d78e52605 | ||
|
|
90136a5562 | ||
|
|
1592767c8c | ||
|
|
afa6ce2113 | ||
|
|
50e6e414ee | ||
|
|
ba9b8edcdc | ||
|
|
d7a927475c | ||
|
|
afe210343f | ||
|
|
4e293daf62 | ||
|
|
f9d7fdc516 | ||
|
|
6a04f3955c | ||
|
|
dce3b1780c | ||
|
|
f47f3e9db6 | ||
|
|
4ac74acaf7 | ||
|
|
cf7588c288 | ||
|
|
ec7bdf4000 | ||
|
|
51cd97f782 | ||
|
|
a16f2f096d | ||
|
|
4e92f14551 | ||
|
|
8f6cc9ff44 | ||
|
|
f885df5c67 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
## v0.11.0
|
||||||
|
|
||||||
|
- 完成导出系统, 支持完整的单帧和帧序列导出功能
|
||||||
|
- 预览画面增加快进功能
|
||||||
|
|
||||||
|
## v0.10.9
|
||||||
|
|
||||||
|
- 预览图导出增加名称后缀参数
|
||||||
|
|
||||||
|
## v0.10.8
|
||||||
|
|
||||||
|
- 完善预览图导出
|
||||||
|
- 优化骨骼文件选择
|
||||||
|
|
||||||
## v0.10.7
|
## v0.10.7
|
||||||
|
|
||||||
- 增加仅导出选中
|
- 增加仅导出选中
|
||||||
|
|||||||
90
README.en.md
90
README.en.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
[中文](README.md) | [English](README.en.md)
|
[中文](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
|
## 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:
|
| Version | View & Export | Format Conversion | Version Conversion |
|
||||||
- [x] `v2.1.x`
|
| :-------: | :--------------------: | :--------------------: | :----------------: |
|
||||||
- [x] `v3.6.x`
|
| `2.1.x` | :white_check_mark: | | |
|
||||||
- [x] `v3.7.x`
|
| `3.1.x` | | | |
|
||||||
- [x] `v3.8.x`
|
| `3.4.x` | | | |
|
||||||
- [x] `v4.0.x`
|
| `3.5.x` | | | |
|
||||||
- [x] `v4.1.x`
|
| `3.6.x` | :white_check_mark: | | |
|
||||||
- [x] `v4.2.x`
|
| `3.7.x` | :white_check_mark: | | |
|
||||||
- [ ] `v4.3.x`
|
| `3.8.x` | :white_check_mark: | :white_check_mark: | |
|
||||||
- Supports animation preview for multi-skeleton files
|
| `4.1.x` | :white_check_mark: | | |
|
||||||
- Allows independent parameter settings for each skeleton
|
| `4.2.x` | :white_check_mark: | | |
|
||||||
- Supports exporting animation as PNG frame sequences
|
| `4.3.x` | | | |
|
||||||
- Provides export settings such as zoom and rotation
|
|
||||||
- More features coming soon...
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Importing Skeletons
|
### 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.
|
||||||
|
|
||||||
Select one or more items in the **Model List** to display adjustable parameters in the **Model Parameters** panel.
|
- 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.
|
||||||
|
|
||||||
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.
|
- **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.
|
||||||
|
|
||||||
### Adjusting the View
|
- 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.
|
||||||
|
|
||||||
Mouse operations supported in the **Preview** window:
|
- **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.
|
||||||
|
|
||||||
- Left-click to drag the skeleton
|
### Adjusting Preview Content
|
||||||
- Right-click to drag the view
|
|
||||||
- Scroll wheel to zoom in/out
|
|
||||||
|
|
||||||
Additionally, you can adjust export and preview parameters through the **View Parameters** panel.
|
The model list supports right-click menus and various shortcut keys, and you can select multiple models to adjust their parameters in bulk.
|
||||||
|
|
||||||
In the **Functions** menu, you can reset and synchronize the animation time for all skeletons.
|
In addition to the parameter panel, the preview area supports several mouse actions:
|
||||||
|
|
||||||
### Exporting Animations
|
- **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.
|
||||||
|
|
||||||
Select **Export** from the **File** menu to export all loaded skeleton animations as PNG frame sequences, based on the current preview settings.
|
In the function menu, you can reset and synchronize the animation time for all skeletons.
|
||||||
|
|
||||||
You can view the full duration of each animation in the **Model Parameters** of each skeleton.
|
### Exporting Preview Content
|
||||||
|
|
||||||
|
Both preview images and videos can be exported.
|
||||||
|
|
||||||
|
- **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! :)*
|
||||||
|
|||||||
90
README.md
90
README.md
@@ -18,62 +18,76 @@
|
|||||||
|
|
||||||
也可以下载带有 `SelfContained` 后缀的压缩包, 可以独立运行.
|
也可以下载带有 `SelfContained` 后缀的压缩包, 可以独立运行.
|
||||||
|
|
||||||
## 功能支持
|
## 版本支持
|
||||||
|
|
||||||
| 版本 | 查看&导出 | 格式转换 |
|
| 版本 | 查看&导出 | 格式转换 | 版本转换 |
|
||||||
| :---: | :---: | :---: |
|
| :---: | :---: | :---: | :---: |
|
||||||
| `2.1.x` | :white_check_mark: | |
|
| `2.1.x` | :white_check_mark: | | |
|
||||||
| `3.1.x` | | |
|
| `3.1.x` | | | |
|
||||||
| `3.4.x` | | |
|
| `3.4.x` | | | |
|
||||||
| `3.5.x` | | |
|
| `3.5.x` | | | |
|
||||||
| `3.6.x` | :white_check_mark: | |
|
| `3.6.x` | :white_check_mark: | | |
|
||||||
| `3.7.x` | :white_check_mark: | |
|
| `3.7.x` | :white_check_mark: | | |
|
||||||
| `3.8.x` | :white_check_mark: | :white_check_mark: |
|
| `3.8.x` | :white_check_mark: | :white_check_mark: | |
|
||||||
| `4.1.x` | :white_check_mark: | |
|
| `4.1.x` | :white_check_mark: | | |
|
||||||
| `4.2.x` | :white_check_mark: | |
|
| `4.2.x` | :white_check_mark: | | |
|
||||||
| `4.3.x` | | |
|
| `4.3.x` | | | |
|
||||||
|
|
||||||
- 支持文件拖放/复制到剪贴板打开
|
|
||||||
- 支持自动检测版本
|
|
||||||
- 支持列表缩略图预览
|
|
||||||
- 支持多骨骼文件动画预览
|
|
||||||
- 支持每个骨骼独立参数设置
|
|
||||||
- 支持动画PNG帧序列导出
|
|
||||||
- 支持缩放旋转等导出画面设置
|
|
||||||
- 支持对独立的骨骼文件进行格式转换
|
|
||||||
- Coming soon...
|
|
||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
### 骨骼导入
|
### 骨骼导入
|
||||||
|
|
||||||
**文件**菜单可以选择**打开**或者**批量打开**进行骨骼文件导入.
|
有 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>
|
||||||
@@ -500,10 +500,8 @@ namespace SpineViewer.Controls
|
|||||||
foreach (int i in listView.SelectedIndices)
|
foreach (int i in listView.SelectedIndices)
|
||||||
{
|
{
|
||||||
var spine = spines[i];
|
var spine = spines[i];
|
||||||
var image = spine.Preview;
|
|
||||||
var path = Path.Combine(Program.TempDir, $"{spine.ID}.png");
|
var path = Path.Combine(Program.TempDir, $"{spine.ID}.png");
|
||||||
using (var clone = new Bitmap(image))
|
spine.Preview.Save(path);
|
||||||
clone.Save(path);
|
|
||||||
fileDropList.Add(path);
|
fileDropList.Add(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
168
SpineViewer/Controls/SpinePreviewer.Designer.cs
generated
168
SpineViewer/Controls/SpinePreviewer.Designer.cs
generated
@@ -28,13 +28,28 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeComponent()
|
private void InitializeComponent()
|
||||||
{
|
{
|
||||||
|
components = new System.ComponentModel.Container();
|
||||||
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SpinePreviewer));
|
||||||
panel = new Panel();
|
panel = new Panel();
|
||||||
|
tableLayoutPanel1 = new TableLayoutPanel();
|
||||||
|
panel_Container = new Panel();
|
||||||
|
flowLayoutPanel1 = new FlowLayoutPanel();
|
||||||
|
button_Stop = new Button();
|
||||||
|
imageList = new ImageList(components);
|
||||||
|
button_Restart = new Button();
|
||||||
|
button_Start = new Button();
|
||||||
|
button_ForwardStep = new Button();
|
||||||
|
button_ForwardFast = new Button();
|
||||||
|
toolTip = new ToolTip(components);
|
||||||
|
tableLayoutPanel1.SuspendLayout();
|
||||||
|
panel_Container.SuspendLayout();
|
||||||
|
flowLayoutPanel1.SuspendLayout();
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
//
|
//
|
||||||
// panel
|
// panel
|
||||||
//
|
//
|
||||||
panel.BackColor = SystemColors.ControlDarkDark;
|
panel.BackColor = SystemColors.ControlDarkDark;
|
||||||
panel.Location = new Point(160, 160);
|
panel.Location = new Point(157, 136);
|
||||||
panel.Margin = new Padding(0);
|
panel.Margin = new Padding(0);
|
||||||
panel.Name = "panel";
|
panel.Name = "panel";
|
||||||
panel.Size = new Size(320, 320);
|
panel.Size = new Size(320, 320);
|
||||||
@@ -44,20 +59,165 @@
|
|||||||
panel.MouseUp += panel_MouseUp;
|
panel.MouseUp += panel_MouseUp;
|
||||||
panel.MouseWheel += panel_MouseWheel;
|
panel.MouseWheel += panel_MouseWheel;
|
||||||
//
|
//
|
||||||
|
// tableLayoutPanel1
|
||||||
|
//
|
||||||
|
tableLayoutPanel1.ColumnCount = 1;
|
||||||
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.Controls.Add(panel_Container, 0, 0);
|
||||||
|
tableLayoutPanel1.Controls.Add(flowLayoutPanel1, 0, 1);
|
||||||
|
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||||
|
tableLayoutPanel1.Location = new Point(0, 0);
|
||||||
|
tableLayoutPanel1.Margin = new Padding(0);
|
||||||
|
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
|
tableLayoutPanel1.RowCount = 2;
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||||
|
tableLayoutPanel1.Size = new Size(641, 636);
|
||||||
|
tableLayoutPanel1.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// panel_Container
|
||||||
|
//
|
||||||
|
panel_Container.BackColor = SystemColors.ControlDark;
|
||||||
|
panel_Container.Controls.Add(panel);
|
||||||
|
panel_Container.Dock = DockStyle.Fill;
|
||||||
|
panel_Container.Location = new Point(0, 0);
|
||||||
|
panel_Container.Margin = new Padding(0);
|
||||||
|
panel_Container.Name = "panel_Container";
|
||||||
|
panel_Container.Size = new Size(641, 594);
|
||||||
|
panel_Container.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// flowLayoutPanel1
|
||||||
|
//
|
||||||
|
flowLayoutPanel1.Anchor = AnchorStyles.None;
|
||||||
|
flowLayoutPanel1.AutoSize = true;
|
||||||
|
flowLayoutPanel1.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
flowLayoutPanel1.Controls.Add(button_Stop);
|
||||||
|
flowLayoutPanel1.Controls.Add(button_Restart);
|
||||||
|
flowLayoutPanel1.Controls.Add(button_Start);
|
||||||
|
flowLayoutPanel1.Controls.Add(button_ForwardStep);
|
||||||
|
flowLayoutPanel1.Controls.Add(button_ForwardFast);
|
||||||
|
flowLayoutPanel1.Location = new Point(138, 594);
|
||||||
|
flowLayoutPanel1.Margin = new Padding(0);
|
||||||
|
flowLayoutPanel1.Name = "flowLayoutPanel1";
|
||||||
|
flowLayoutPanel1.Size = new Size(365, 42);
|
||||||
|
flowLayoutPanel1.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// button_Stop
|
||||||
|
//
|
||||||
|
button_Stop.AutoSize = true;
|
||||||
|
button_Stop.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
button_Stop.ImageKey = "stop";
|
||||||
|
button_Stop.ImageList = imageList;
|
||||||
|
button_Stop.Location = new Point(3, 3);
|
||||||
|
button_Stop.Name = "button_Stop";
|
||||||
|
button_Stop.Padding = new Padding(15, 3, 15, 3);
|
||||||
|
button_Stop.Size = new Size(67, 36);
|
||||||
|
button_Stop.TabIndex = 0;
|
||||||
|
toolTip.SetToolTip(button_Stop, "停止播放并重置时间到初始");
|
||||||
|
button_Stop.UseVisualStyleBackColor = true;
|
||||||
|
button_Stop.Click += button_Stop_Click;
|
||||||
|
//
|
||||||
|
// imageList
|
||||||
|
//
|
||||||
|
imageList.ColorDepth = ColorDepth.Depth32Bit;
|
||||||
|
imageList.ImageStream = (ImageListStreamer)resources.GetObject("imageList.ImageStream");
|
||||||
|
imageList.TransparentColor = Color.Transparent;
|
||||||
|
imageList.Images.SetKeyName(0, "stop");
|
||||||
|
imageList.Images.SetKeyName(1, "restart");
|
||||||
|
imageList.Images.SetKeyName(2, "start");
|
||||||
|
imageList.Images.SetKeyName(3, "pause");
|
||||||
|
imageList.Images.SetKeyName(4, "forward-step");
|
||||||
|
imageList.Images.SetKeyName(5, "forward-fast");
|
||||||
|
//
|
||||||
|
// button_Restart
|
||||||
|
//
|
||||||
|
button_Restart.AutoSize = true;
|
||||||
|
button_Restart.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
button_Restart.ImageKey = "restart";
|
||||||
|
button_Restart.ImageList = imageList;
|
||||||
|
button_Restart.Location = new Point(76, 3);
|
||||||
|
button_Restart.Name = "button_Restart";
|
||||||
|
button_Restart.Padding = new Padding(15, 3, 15, 3);
|
||||||
|
button_Restart.Size = new Size(67, 36);
|
||||||
|
button_Restart.TabIndex = 1;
|
||||||
|
toolTip.SetToolTip(button_Restart, "从头开始播放");
|
||||||
|
button_Restart.UseVisualStyleBackColor = true;
|
||||||
|
button_Restart.Click += button_Restart_Click;
|
||||||
|
//
|
||||||
|
// button_Start
|
||||||
|
//
|
||||||
|
button_Start.AutoSize = true;
|
||||||
|
button_Start.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
button_Start.BackgroundImageLayout = ImageLayout.Center;
|
||||||
|
button_Start.ImageKey = "pause";
|
||||||
|
button_Start.ImageList = imageList;
|
||||||
|
button_Start.Location = new Point(149, 3);
|
||||||
|
button_Start.Name = "button_Start";
|
||||||
|
button_Start.Padding = new Padding(15, 3, 15, 3);
|
||||||
|
button_Start.Size = new Size(67, 36);
|
||||||
|
button_Start.TabIndex = 2;
|
||||||
|
toolTip.SetToolTip(button_Start, "开始/暂停");
|
||||||
|
button_Start.UseVisualStyleBackColor = true;
|
||||||
|
button_Start.Click += button_Start_Click;
|
||||||
|
//
|
||||||
|
// button_ForwardStep
|
||||||
|
//
|
||||||
|
button_ForwardStep.AutoSize = true;
|
||||||
|
button_ForwardStep.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
button_ForwardStep.ImageKey = "forward-step";
|
||||||
|
button_ForwardStep.ImageList = imageList;
|
||||||
|
button_ForwardStep.Location = new Point(222, 3);
|
||||||
|
button_ForwardStep.Name = "button_ForwardStep";
|
||||||
|
button_ForwardStep.Padding = new Padding(15, 3, 15, 3);
|
||||||
|
button_ForwardStep.Size = new Size(67, 36);
|
||||||
|
button_ForwardStep.TabIndex = 3;
|
||||||
|
toolTip.SetToolTip(button_ForwardStep, "快进 1 帧");
|
||||||
|
button_ForwardStep.UseVisualStyleBackColor = true;
|
||||||
|
button_ForwardStep.Click += button_ForwardStep_Click;
|
||||||
|
//
|
||||||
|
// button_ForwardFast
|
||||||
|
//
|
||||||
|
button_ForwardFast.AutoSize = true;
|
||||||
|
button_ForwardFast.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
button_ForwardFast.ImageKey = "forward-fast";
|
||||||
|
button_ForwardFast.ImageList = imageList;
|
||||||
|
button_ForwardFast.Location = new Point(295, 3);
|
||||||
|
button_ForwardFast.Name = "button_ForwardFast";
|
||||||
|
button_ForwardFast.Padding = new Padding(15, 3, 15, 3);
|
||||||
|
button_ForwardFast.Size = new Size(67, 36);
|
||||||
|
button_ForwardFast.TabIndex = 4;
|
||||||
|
toolTip.SetToolTip(button_ForwardFast, "快进 10 帧");
|
||||||
|
button_ForwardFast.UseVisualStyleBackColor = true;
|
||||||
|
button_ForwardFast.Click += button_ForwardFast_Click;
|
||||||
|
//
|
||||||
// SpinePreviewer
|
// SpinePreviewer
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
BackColor = SystemColors.ControlDark;
|
Controls.Add(tableLayoutPanel1);
|
||||||
Controls.Add(panel);
|
|
||||||
Name = "SpinePreviewer";
|
Name = "SpinePreviewer";
|
||||||
Size = new Size(640, 640);
|
Size = new Size(641, 636);
|
||||||
SizeChanged += SpinePreviewer_SizeChanged;
|
SizeChanged += SpinePreviewer_SizeChanged;
|
||||||
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
|
tableLayoutPanel1.PerformLayout();
|
||||||
|
panel_Container.ResumeLayout(false);
|
||||||
|
flowLayoutPanel1.ResumeLayout(false);
|
||||||
|
flowLayoutPanel1.PerformLayout();
|
||||||
ResumeLayout(false);
|
ResumeLayout(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private Panel panel;
|
private Panel panel;
|
||||||
|
private TableLayoutPanel tableLayoutPanel1;
|
||||||
|
private Panel panel_Container;
|
||||||
|
private FlowLayoutPanel flowLayoutPanel1;
|
||||||
|
private Button button_Stop;
|
||||||
|
private Button button_Start;
|
||||||
|
private ImageList imageList;
|
||||||
|
private ToolTip toolTip;
|
||||||
|
private Button button_ForwardStep;
|
||||||
|
private Button button_ForwardFast;
|
||||||
|
private Button button_Restart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,45 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Security.Policy;
|
using System.Security.Policy;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using NLog.Targets;
|
|
||||||
|
|
||||||
namespace SpineViewer.Controls
|
namespace SpineViewer.Controls
|
||||||
{
|
{
|
||||||
public partial class SpinePreviewer : UserControl
|
public partial class SpinePreviewer : UserControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 要绑定的 Spine 列表控件
|
||||||
|
/// </summary>
|
||||||
|
[Category("自定义"), Description("相关联的 SpineListView")]
|
||||||
|
public SpineListView? SpineListView { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 属性信息面板
|
||||||
|
/// </summary>
|
||||||
|
[Category("自定义"), Description("用于显示画面属性的属性页")]
|
||||||
|
public PropertyGrid? PropertyGrid
|
||||||
|
{
|
||||||
|
get => propertyGrid;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
propertyGrid = value;
|
||||||
|
if (propertyGrid is not null)
|
||||||
|
propertyGrid.SelectedObject = new PreviewerProperty(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private PropertyGrid? propertyGrid;
|
||||||
|
|
||||||
|
#region 画面参数
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面缩放最大值
|
||||||
|
/// </summary>
|
||||||
|
public const float ZOOM_MAX = 1000f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面缩放最小值
|
||||||
|
/// </summary>
|
||||||
|
public const float ZOOM_MIN = 0.001f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 包装类, 用于属性面板显示
|
/// 包装类, 用于属性面板显示
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -50,74 +83,6 @@ namespace SpineViewer.Controls
|
|||||||
public uint MaxFps { get => previewer.MaxFps; set => previewer.MaxFps = value; }
|
public uint MaxFps { get => previewer.MaxFps; set => previewer.MaxFps = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 要绑定的 Spine 列表控件
|
|
||||||
/// </summary>
|
|
||||||
[Category("自定义"), Description("相关联的 SpineListView")]
|
|
||||||
public SpineListView? SpineListView { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性信息面板
|
|
||||||
/// </summary>
|
|
||||||
[Category("自定义"), Description("用于显示画面属性的属性页")]
|
|
||||||
public PropertyGrid? PropertyGrid
|
|
||||||
{
|
|
||||||
get => propertyGrid;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
propertyGrid = value;
|
|
||||||
if (propertyGrid is not null)
|
|
||||||
propertyGrid.SelectedObject = new PreviewerProperty(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private PropertyGrid? propertyGrid;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 画面缩放最大值
|
|
||||||
/// </summary>
|
|
||||||
public const float ZOOM_MAX = 1000f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 画面缩放最小值
|
|
||||||
/// </summary>
|
|
||||||
public const float ZOOM_MIN = 0.001f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览画面背景色
|
|
||||||
/// </summary>
|
|
||||||
private static readonly SFML.Graphics.Color BackgroundColor = new(105, 105, 105);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览画面坐标轴颜色
|
|
||||||
/// </summary>
|
|
||||||
private static readonly SFML.Graphics.Color AxisColor = new(220, 220, 220);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 坐标轴顶点缓冲区
|
|
||||||
/// </summary>
|
|
||||||
private readonly SFML.Graphics.VertexArray AxisVertex = new(SFML.Graphics.PrimitiveType.Lines, 2);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 渲染窗口
|
|
||||||
/// </summary>
|
|
||||||
private readonly SFML.Graphics.RenderWindow RenderWindow;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 帧间隔计时器
|
|
||||||
/// </summary>
|
|
||||||
private readonly SFML.System.Clock Clock = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 画面拖放对象世界坐标源点
|
|
||||||
/// </summary>
|
|
||||||
private SFML.System.Vector2f? draggingSrc = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 渲染任务
|
|
||||||
/// </summary>
|
|
||||||
private Task? task = null;
|
|
||||||
private CancellationTokenSource? cancelToken = null;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 分辨率
|
/// 分辨率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -280,6 +245,13 @@ namespace SpineViewer.Controls
|
|||||||
public uint MaxFps { get => maxFps; set { RenderWindow.SetFramerateLimit(value); maxFps = value; } }
|
public uint MaxFps { get => maxFps; set { RenderWindow.SetFramerateLimit(value); maxFps = value; } }
|
||||||
private uint maxFps = 60;
|
private uint maxFps = 60;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取 View
|
||||||
|
/// </summary>
|
||||||
|
public SFML.Graphics.View GetView() => RenderWindow.GetView();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public SpinePreviewer()
|
public SpinePreviewer()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -293,27 +265,37 @@ namespace SpineViewer.Controls
|
|||||||
MaxFps = 30;
|
MaxFps = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
#region 渲染线程管理
|
||||||
/// 预览画面帧参数
|
|
||||||
/// </summary>
|
|
||||||
public SpinePreviewerFrameArgs GetFrameArgs() => new(Resolution, RenderWindow.GetView(), RenderSelectedOnly);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始预览
|
/// 渲染窗口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartPreview()
|
private readonly SFML.Graphics.RenderWindow RenderWindow;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 渲染任务
|
||||||
|
/// </summary>
|
||||||
|
private Task? task = null;
|
||||||
|
private CancellationTokenSource? cancelToken = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始渲染
|
||||||
|
/// </summary>
|
||||||
|
public void StartRender()
|
||||||
{
|
{
|
||||||
if (task is not null)
|
if (task is not null)
|
||||||
return;
|
return;
|
||||||
cancelToken = new();
|
cancelToken = new();
|
||||||
task = Task.Run(RenderTask, cancelToken.Token);
|
task = Task.Run(RenderTask, cancelToken.Token);
|
||||||
|
IsUpdating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 停止预览
|
/// 停止渲染
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void StopPreview()
|
public void StopRender()
|
||||||
{
|
{
|
||||||
|
IsUpdating = false;
|
||||||
if (task is null || cancelToken is null)
|
if (task is null || cancelToken is null)
|
||||||
return;
|
return;
|
||||||
cancelToken.Cancel();
|
cancelToken.Cancel();
|
||||||
@@ -322,6 +304,58 @@ namespace SpineViewer.Controls
|
|||||||
task = null;
|
task = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 渲染更新管理
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否更新画面
|
||||||
|
/// </summary>
|
||||||
|
public bool IsUpdating
|
||||||
|
{
|
||||||
|
get => isUpdating;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (value == isUpdating) return;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
button_Start.ImageKey = "pause";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
button_Start.ImageKey = "start";
|
||||||
|
}
|
||||||
|
isUpdating = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool isUpdating = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 快进时间量
|
||||||
|
/// </summary>
|
||||||
|
private float forwardDelta = 0;
|
||||||
|
private object _forwardDeltaLock = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览画面背景色
|
||||||
|
/// </summary>
|
||||||
|
private static readonly SFML.Graphics.Color BackgroundColor = new(105, 105, 105);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览画面坐标轴颜色
|
||||||
|
/// </summary>
|
||||||
|
private static readonly SFML.Graphics.Color AxisColor = new(220, 220, 220);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 坐标轴顶点缓冲区
|
||||||
|
/// </summary>
|
||||||
|
private readonly SFML.Graphics.VertexArray AxisVertex = new(SFML.Graphics.PrimitiveType.Lines, 2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧间隔计时器
|
||||||
|
/// </summary>
|
||||||
|
private readonly SFML.System.Clock Clock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 渲染任务
|
/// 渲染任务
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -362,6 +396,17 @@ namespace SpineViewer.Controls
|
|||||||
break; // 提前中止
|
break; // 提前中止
|
||||||
|
|
||||||
var spine = spines[i];
|
var spine = spines[i];
|
||||||
|
|
||||||
|
// 停止更新的时候只是时间不前进, 但是坐标变换还是要更新, 否则无法移动对象
|
||||||
|
if (!IsUpdating) delta = 0;
|
||||||
|
|
||||||
|
// 加上要快进的量
|
||||||
|
lock (_forwardDeltaLock)
|
||||||
|
{
|
||||||
|
delta += forwardDelta;
|
||||||
|
forwardDelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
spine.Update(delta);
|
spine.Update(delta);
|
||||||
|
|
||||||
if (RenderSelectedOnly && !spine.IsSelected)
|
if (RenderSelectedOnly && !spine.IsSelected)
|
||||||
@@ -383,13 +428,20 @@ namespace SpineViewer.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面拖放对象世界坐标源点
|
||||||
|
/// </summary>
|
||||||
|
private SFML.System.Vector2f? draggingSrc = null;
|
||||||
|
|
||||||
private void SpinePreviewer_SizeChanged(object sender, EventArgs e)
|
private void SpinePreviewer_SizeChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (RenderWindow is null)
|
if (RenderWindow is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float parentX = Width;
|
float parentX = panel.Parent.Width;
|
||||||
float parentY = Height;
|
float parentY = panel.Parent.Height;
|
||||||
float sizeX = panel.Width;
|
float sizeX = panel.Width;
|
||||||
float sizeY = panel.Height;
|
float sizeY = panel.Height;
|
||||||
|
|
||||||
@@ -538,27 +590,58 @@ namespace SpineViewer.Controls
|
|||||||
Zoom *= (e.Delta > 0 ? 1.1f : 0.9f);
|
Zoom *= (e.Delta > 0 ? 1.1f : 0.9f);
|
||||||
PropertyGrid?.Refresh();
|
PropertyGrid?.Refresh();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
private void button_Stop_Click(object sender, EventArgs e)
|
||||||
/// 预览画面帧参数
|
|
||||||
/// </summary>
|
|
||||||
public class SpinePreviewerFrameArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
IsUpdating = false;
|
||||||
/// 分辨率
|
if (SpineListView is not null)
|
||||||
/// </summary>
|
{
|
||||||
public Size Resolution => resolution;
|
lock (SpineListView.Spines)
|
||||||
|
{
|
||||||
/// <summary>
|
foreach (var spine in SpineListView.Spines)
|
||||||
/// 渲染视窗
|
spine.CurrentAnimation = spine.CurrentAnimation;
|
||||||
/// </summary>
|
}
|
||||||
public SFML.Graphics.View View => view;
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否仅渲染/导出选中骨骼
|
|
||||||
/// </summary>
|
|
||||||
public bool RenderSelectedOnly => renderSelectedOnly;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void button_Restart_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (SpineListView is not null)
|
||||||
|
{
|
||||||
|
lock (SpineListView.Spines)
|
||||||
|
{
|
||||||
|
foreach (var spine in SpineListView.Spines)
|
||||||
|
spine.CurrentAnimation = spine.CurrentAnimation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IsUpdating = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_Start_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
IsUpdating = !IsUpdating;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_ForwardStep_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
lock (_forwardDeltaLock)
|
||||||
|
{
|
||||||
|
forwardDelta += 1f / maxFps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_ForwardFast_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
lock (_forwardDeltaLock)
|
||||||
|
{
|
||||||
|
forwardDelta += 10f / maxFps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public void ClickStopButton() => button_Stop_Click(button_Stop, EventArgs.Empty);
|
||||||
|
//public void ClickRestartButton() => button_Restart_Click(button_Restart, EventArgs.Empty);
|
||||||
|
//public void ClickStartButton() => button_Start_Click(button_Start, EventArgs.Empty);
|
||||||
|
//public void ClickForwardStepButton() => button_ForwardStep_Click(button_ForwardStep, EventArgs.Empty);
|
||||||
|
//public void ClickForwardFastButton() => button_ForwardFast_Click(button_ForwardFast, EventArgs.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,4 +117,210 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<metadata name="imageList.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
|
<data name="imageList.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>
|
||||||
|
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
|
||||||
|
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
|
||||||
|
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAHi0AAAJNU0Z0AUkBTAIBAQYB
|
||||||
|
AAFwAQABcAEAAR8BAAEYAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABfAMAATADAAEBAQABIAYAAV0q
|
||||||
|
AAQCAy0BRQNbAc0DXQHoA1kBxgMyAU8DDwEUBAIYAAMOARIDQwF3A10BzwNbAc0DLQFFBAIYAANWAbID
|
||||||
|
XQHoA1wB1gNDAXcDFgEeBAIYAAMKAQ0DSQGFA14B4wNfAeUDUQGeAyQBNAMJAQsEARgAAwsBDgM7AWQD
|
||||||
|
XgHSA1YBsv8AEQAEAgMxAUwDYQHhAwAB/wMuAfkDYAHbA0QBewMeASoDBgEIFAADGAEhA1cBwgMhAfsD
|
||||||
|
YQHhAzEBTAQCGAADWQHDAwAB/wMhAfwDXAHrA0gBhAMWAR4YAAMLAQ4DTQGSAysB+QMPAf4DUAHyA1gB
|
||||||
|
ugM3AVoDEQEWAwIBAxQAAxcBHwNJAYYDXAHrA1kBw/8AEQAEAgMxAUwDYQHhAwAB/wMAAf8DHgH9A2AB
|
||||||
|
4ANQAZoDLgFGAxEBFgMGAQcEAQgAAxoBJANbAc0DAAH/A2EB4QMxAUwEAhgAA1kBwwMAAf8DAAH/AwAB
|
||||||
|
/wNbAdADPgFrAw8BEwMCAQMQAAMLAQ4DTQGSAysB+QMAAf8DAAH/AzkB9gNcAcsDRAF5Ax4BKgMGAQcM
|
||||||
|
AAQBAxgBIQNKAYsDWwHsA1kBw/8AEQAEAgMxAUwDYQHhAwAB/wMuAfkDXAHnA0MB9QNWAe4DWQG7A0MB
|
||||||
|
dwMoATsDDwEUBAEEAAMaASQDWwHNAwAB/wNhAeEDMQFMBAIYAANZAcMDIAH8A1AB8ANDAfUDLgH5A10B
|
||||||
|
zgNDAXcDGgEjAwIBAwwAAwsBDgNNAZIDKwH5AwEB/wMkAfoDOgH4Ay4B+QNdAeMDTgGYAyQBNQMGAQgE
|
||||||
|
AQQABAEDGAEhA0oBiwNbAewDWQHD/wARAAQCAzEBTANhAeEDAAH/A1wB2QM7AWMDWQG7Az0B9wM5AfgD
|
||||||
|
XAHnA1sBxQNBAXMDEwEZAwIBAwMaASQDWwHNAwAB/wNhAeEDMQFMBAIYAANZAcMDXAHrA1ABmgNVAbED
|
||||||
|
TQHzAyEB+wNbAeQDSwGPAxsBJQMDAQQIAAMLAQ4DTQGSAysB+QMfAf0DXAHZA1oBxwNDAfUDDwH+A1wB
|
||||||
|
6wNSAaMDJQE3AwMBBAQABAEDGAEhA0oBiwNbAewDWQHD/wARAAQCAzEBTANhAeEDAAH/A1sBzQMaASQD
|
||||||
|
FgEdA1UBrwMAAf8DAAH/AwAB/wMAAf8DVQGvAxYBHQMaASQDWwHNAwAB/wNhAeEDMQFMBAIYAANZAcMD
|
||||||
|
WwHkAzsBZQMHAQkDSQGGAyEB+wMAAf8DAAH/A1kBwQMdASkIAAMLAQ4DTQGSAysB+QMrAfkDTQGSAzkE
|
||||||
|
XgHiAwAB/wMAAf8DXQHjAzYBWAMFAQYEAAQBAxgBIQNKAYsDWwHsA1kBw/8AEQAEAgMxAUwDYQHhAwAB
|
||||||
|
/wNbAc0DGgEkAwIBAwMTARoDRgF/A1sB3gMhAfsDDwH+AzkB+ANZAbsDOwFjA1wB2QMAAf8DYQHhAzEB
|
||||||
|
TAQCGAADWQHDA1sB5AM7AWUDBwQJAQwDOgFhA18B1QNCAfUDLgH5A1sBygMyAU8DDwEUAw0BEQNNAZID
|
||||||
|
KwH5AysB+QNNAZIDEQEWAy0BRANaAb8DUgHvAyEB+wNdAdwDPwFuAxYBHgMEAQUDGAEhA0oBiwNbAewD
|
||||||
|
WQHD/wARAAQCAzEBTANhAeEDAAH/A1sBzQMaASQEAAQCAxMBGgM9AWcDWQHAA1IB7wMPAf4DPQH3A1wB
|
||||||
|
5wMuAfkDAAH/A2EB4QMxAUwEAhgAA1kBwwNbAeQDOwFlAwcBCQQAAwsBDgMxAU0DWAG9AzkB9gMuAfkD
|
||||||
|
YAHbA0QBeAMhAS8DTgGVAysB+QMrAfkDTQGSAwsBDgMGAQgDIAEuA00BkgNdAdwDQwH1A1oB6QNOAZYD
|
||||||
|
KAE8AyABLQNLAY0DWwHsA1kBw/8AEQAEAgMxAUwDYQHhAwAB/wNbAc0DGgEkCAAEAgMMARADLwFJA1IB
|
||||||
|
owNbAeQDPQH3Aw8B/gMAAf8DAAH/A2EB4QMxAUwEAhgAA1kBwwNbAeQDOwFlAwcBCQgAAxABFQM/AW0D
|
||||||
|
XAHWAyQB+gMeAf0DXAHWA0QBeQNUAasDIQH7AysB+QNNAZIDCwEOBAADAwEEAxsBJgNBAXMDWgHEA0UB
|
||||||
|
9ANWAe4DVQG0A0QBegNRAaIDVgHuA1kBw/8AEQAEAgMxAUwDYQHhAwAB/wNbAc0DGgEkEAADCAEKAyMB
|
||||||
|
MwNEAXkDVwG8A18B5QMkAfoDAAH/A2EB4QMxAUwEAhgAA1kBwwNbAeQDOwFlAwcBCQgAAwMBBAMaASQD
|
||||||
|
QgF0A14B0gMhAfsDOQH2A10B0QNgAeADHgH9AysB+QNNAZIDCwEOCAADAgEDAxIBFwM1AVUDWAG6A1UB
|
||||||
|
8QM5AfYDWwHeA2AB2wM5AfgDWQHD/wARAAQCAzEBTANhAeEDAAH/A1sBzQMaASQUAAMCAQMDDgESAyMB
|
||||||
|
MgM9AWgDXgHdAwAB/wNhAeEDMQFMBAIYAANZAcMDWwHkAzsBZQMHAQkMAAMCAQMDDwETAzQBUwNdAdED
|
||||||
|
OQH4Ax8B/AMfAf0DAAH/AysB+QNNAZIDCwEODAAEAQMJAQwDIwEzA1UBrgMgAf0DHgH9Ax8B/AMPAf4D
|
||||||
|
WQHD/wARAAQCAzEBTANhAeEDAAH/A1sBzQMaASQgAAMaASQDWwHNAwAB/wNhAeEDMQFMBAIYAANZAcMD
|
||||||
|
WwHkAzsBZQMHAQkYAAMPARQDVwG5AwAB/wMAAf8DAAH/AysB+QNNAZIDCwEOGAADRwGAA1wB7QMAAf8D
|
||||||
|
AAH/AwAB/wNZAcP/ABEABAIDMQFMA2EB4QMAAf8DWwHNAxoBJBQABAIDBwEJAxYBHQM1AVUDXAHZAwAB
|
||||||
|
/wNhAeEDMQFMBAIYAANZAcMDWwHkAzsBZQMHAQkMAAQBAw0BEQM0AVMDXQHRAy4B+QMQAf4DDwH+AwAB
|
||||||
|
/wMrAfkDTQGSAwsBDgwABAEDCQELAx4BKwNTAakDIAH9Ax4B/QMfAfwDDwH+A1kBw/8AEQAEAgMxAUwD
|
||||||
|
YQHhAwAB/wNbAc0DGgEkEAADBwEJAxsBJgM0AVMDTQGSA14B3QMuAfkDAAH/A2EB4QMxAUwEAhgAA1kB
|
||||||
|
wwNbAeQDOwFlAwcBCQgABAIDEAEVAzkBXgNbAc0DIQH7AyEB+wNcAecDVgHuAw8B/gMrAfkDTQGSAwsB
|
||||||
|
DggAAwIBAwMSARcDNQFVA1gBuANVAfEDOQH2A1sB3gNgAdsDOQH4A1kBw/8AEQAEAgMxAUwDYQHhAwAB
|
||||||
|
/wNbAc0DGgEkCAAEAgMMARADLgFGA00BkgNcAcgDXAHrAx4B/QMAAf8DAAH/A2EB4QMxAUwEAhgAA1kB
|
||||||
|
wwNbAeQDOwFlAwcBCQgAAwkBDAMxAU4DWAG3A00B8wMeAf0DXgHdA04BlgNZAb4DHwH8AysB+QNNAZID
|
||||||
|
CwEOBAADAwEEAxsBJgNBAXMDWgHEA0UB9ANWAe4DVQG0A0QBegNRAaIDVgHuA1kBw/8AEQAEAgMxAUwD
|
||||||
|
YQHhAwAB/wNbAc0DGgEkBAAEAgMTARoDPQFnA1oBvwNcAesDJAH6AzoB9gNcAecDLgH5AwAB/wNhAeED
|
||||||
|
MQFMBAIYAANZAcMDWwHkAzsBZQMHAQkEAAMLAQ4DLgFHA1UBrQNSAe8DOgH4A2AB2wNEAXoDJAE1A04B
|
||||||
|
mAMjAfoDKwH5A00BkgMLAQ4DBgEIAyABLgNNAZIDXQHcA0MB9QNaAekDTgGWAygBPAMgAS0DSwGNA1sB
|
||||||
|
7ANZAcP/ABEABAIDMQFMA2EB4QMAAf8DWwHNAxoBJAMCAQMDEwEaA0YBfwNbAd4DIQH7Aw8B/gM5AfgD
|
||||||
|
WQG7AzsBYwNcAdkDAAH/A2EB4QMxAUwEAhgAA1kBwwNbAeQDOwFlAwcECQEMAzoBYQNdAdQDRQH0Ay4B
|
||||||
|
+QNbAcoDMgFPAw8BFAMNAREDTQGSAysB+QMrAfkDTQGSAxEBFgMtAUQDWgG/A1IB7wMgAfwDYAHgA0AB
|
||||||
|
cQMXAR8DBAEFAxgBIQNKAYsDWwHsA1kBw/8AEQAEAgMxAUwDYQHhAwAB/wNbAc0DGgEkAxYBHQNVAa8D
|
||||||
|
AAH/AwAB/wMAAf8DAAH/A1UBrwMWAR0DGgEkA1sBzQMAAf8DYQHhAzEBTAQCGAADWQHDA1sB5AM7AWUD
|
||||||
|
BwEJA0kBhgMhAfsDAAH/AwAB/wNZAcEDHQEpCAADCwEOA00BkgMrAfkDKwH5A00BkgM5BF4B4gMAAf8D
|
||||||
|
AAH/A1gB7QNKAYsDGAEgCAEDGAEhA0oBiwNbAewDWQHD/wARAAQCAzEBTANhAeEDAAH/A1wB2QM7AWMD
|
||||||
|
WQG7Az0B9wMgAfwDRQH0A1wB2QNGAX4DEwEaAwIBAwMaASQDWwHNAwAB/wNhAeEDMQFMBAIYAANZAcMD
|
||||||
|
XAHrA1ABmgNVAbEDTQHzAyEB+wNfAeUDSwGPAxsBJQMDAQQIAAMLAQ4DTQGSAysB+QMhAfsDVgGzA0wB
|
||||||
|
jgNcAesDDwH+A1AB8ANXAbkDLgFHAwYBCAQABAEDGAEhA0oBiwNbAewDWQHD/wARAAQCAzEBTANhAeED
|
||||||
|
AAH/Ay4B+QNcAecDQwH1A1QB8QNbAdMDUQGkAzgBWwMTARkEAgQAAxoBJANbAc0DAAH/A2EB4QMxAUwE
|
||||||
|
AhgAA1kBwwMgAfwDUAHwA0MB9QMfAf0DXgHXA0YBfgMaASQDAgEDDAADCwEOA00BkgMrAfkDDwH+A00B
|
||||||
|
8wNWAe4DPQH3A10B4wNOAZgDJwE5AwgBCgQBBAAEAQMYASEDSgGLA1sB7ANZAcP/ABEABAIDMQFMA2EB
|
||||||
|
4QMAAf8DAAH/Ax4B/QNhAeEDUgGjAzsBYwMhAS8DCgENBAIIAAMaASQDWwHNAwAB/wNhAeEDMQFMBAIY
|
||||||
|
AANZAcMDAAH/AwAB/wMAAf8DXQHoA0oBiwMWAR0DBAEFEAADCwEOA00BkgMrAfkDAAH/AwAB/wM5AfYD
|
||||||
|
XAHLA0QBeQMeASoDBgEHDAAEAQMYASEDSgGLA1sB7ANZAcP/ABEABAIDMQFMA2EB4QMAAf8DLgH5A2AB
|
||||||
|
2wNFAXwDIQEwAwwBEAMDAQQQAAMaASMDXAHIAx8B/QNhAeEDMQFMBAIYAANZAcMDAAH/AyEB/ANcAesD
|
||||||
|
TgGXAyMBMwQCFAADCwEOA00BkgMrAfkDDwH+A1AB8gNYAboDNwFaAxEBFgMCAQMUAAMXAR8DSQGGA1wB
|
||||||
|
6wNZAcP/ABEABAIDLQFFA14B0gNQAfIDXQHJAzIBTwMQARUDAgEDGAADEwEaA1ABnwNbAeQDWwHQAy0B
|
||||||
|
RQQCGAADVQG0A1cB7gNfAdoDRAF4AxgBIAMDAQQYAAMKAQ0DSQGGA10B6ANaAekDUAGfAyQBNAMJAQsE
|
||||||
|
ARgAAwsBDgM7AWUDWwHTA1YBsv8AFQADAwEEAycBOgM/AW0DFAEbKAADDwETAzEBTgMdASkDAgEDHAAD
|
||||||
|
DgESAzEBTQMjATMDBAEFJAADBgEHAygBPAMoATwDBgEHJAAEAQMHAQkDCwEOAwIBA/8ABQADAgEDAw8B
|
||||||
|
FANJAYgDXwHlA10B6ANdAegDXQHoA10B6ANdAegDXQHoA10B6ANdAegDXQHoA10B6ANdAegDXQHoA10B
|
||||||
|
6ANdAegDXQHoA10B6ANdAegDXQHoA1sB5ANGAX4DBQEGBAEoAAMCAQMDDQERAx8BLAMtAUYDVwG5A10B
|
||||||
|
6ANdAegDXQHoA10B6ANdAegDXQHoA18B4wNZAb4DMgFPAw8BEwMCAQMwAAMTARkDRgF+A10B6ANdAegD
|
||||||
|
WQHBAzkBXgMmATgDDwEUBAJcAAM5AV8DXgHiA1wB5wNdAegDXQHoA10B6ANdAegDXQHcAzwBZgMGAQgD
|
||||||
|
BgEIAzwBZgNdAdwDXQHoA10B6ANdAegDXQHoA10B3ANQAZ0DJQE2IAADDAEQAzwBZgNdAc8DHgH9AyQB
|
||||||
|
+gNSAe8DWAHtA1gB7QNYAe0DWAHtA1gB7QNYAe0DWAHtA1gB7QNYAe0DWAHtA1gB7QNYAe0DWAHtA1gB
|
||||||
|
7QNSAe8DJAH6AyAB/ANWAbUDKwFCAwgBCiQABAIDGAEhA0ABcANaAb8DXQHfA1oB7QNSAe8DWwHsA14B
|
||||||
|
5gNfAeUDWAHqA1gB7QNQAfADOgH2A10B0QNDAXcDHgErAwYBBywAAz0BaQNbAd4DAQH/Ay4B+QNcAewD
|
||||||
|
WwHkA14B1wNEAXsDHgEqAwYBCFgAAz8BbAMfAf0DOQH4A1IB7wNYAe0DVgHuAyQB+gM5AfYDTwGbAx4B
|
||||||
|
KwMgAS0DUAGdAzkB9gMkAfoDVgHuA1gB7QNSAe8DPQH3A1AB8gM7AWUgAAMTARkDUAGcAz0B9wM6AfYD
|
||||||
|
XQHMA0sBjQNGAYADRgGAA0YBgANGAYADRgGAA0YBgANGAYADRgGAA0YBgANGAYADRgGAA0YBgANGAYAD
|
||||||
|
RgGAA0sBjwNcAdkDHgH9A1QB8QNOAZQDEgEYJAADBQEGAzEBTgNbAdADUAHyA14B4gNVAa4DSgGKA0YB
|
||||||
|
fwNDAXcDQwF2A0UBfANGAYADTwGbA14B3QNdAegDXwHaA04BlgMoATwDCQEMKAADRwGDAzkB+AMgAfwD
|
||||||
|
WwHTA1MBpgNcAdkDLgH5A2AB4ANQAZoDLQFEAwsBDlQAAz8BbAMgAfwDWwHTA0wBjgNGAYADSgGKA10B
|
||||||
|
3AMfAf0DXgHdAzoBYAM6AWIDXQHfAx4B/QNdAdwDSgGKA0YBgANMAY4DWwHTAyAB/AM/AWwgAAMUARsD
|
||||||
|
UgGlAx0B/QNbAdADPwFsAxgBIQMOARIDDgESAw4BEgMOARIDDgESAw4BEgMOARIDDgESAw4BEgMOARID
|
||||||
|
DgESAw4BEgMOARIDDgESAyABLgNXAbkDHgH9Ax0B/QNSAaUDFAEbJAADBQEGAzEBTQNaAccDXAHIA0AB
|
||||||
|
bwMlATcDEwEaAw4BEgMNAREDDAEQAw4BEgMOARIDHQEoAzoBYANLAY8DWwHYA14B5gNWAbYDMQFNAwYB
|
||||||
|
CCQAA0kBhgMhAfsDLgH5A1UBrgMqAUADPwFtA10B0QNDAfUDVgHuA1gBtwM2AVcDFgEdAwwBEAQCSAAD
|
||||||
|
PwFsAy4B+QNVAa4DIAEtAw4BEgMbASUDWQG+AwAB/wNYAe0DPwFtAz8BbQNYAe0DAAH/A1kBvgMbASUD
|
||||||
|
DgESAyABLQNVAa4DLgH5Az8BbCAAAxQBGwNSAaUDHQH9A1YBtgMoATwDCAEKOAADFgEeA1YBswMeAf0D
|
||||||
|
HQH9A1IBpQMUARskAAQBAw8BFAMjATMDIQEwAwsBDgMDAQQEARQABAIDBwEJAx4BKgNLAYwDXQHfAz0B
|
||||||
|
9wNTAakDKAE7JAADSQGGAyEB+wMuAfkDUwGnAxYBHgMMARADKgFAA1gBugNOAfMDRgH0A2AB2wNXAbwD
|
||||||
|
QgF0AxMBGQMCAQNEAAM/AWwDLgH5A1MBpwMVARwEAAMPARQDVwG5AwAB/wNYAe0DPwFtAz8BbQNYAe0D
|
||||||
|
AAH/A1cBuQMPARQEAAMVARwDUwGnAy4B+QM/AWwgAAMUARsDUgGlAx0B/QNVAbQDJgE4AwcBCTgAAxYB
|
||||||
|
HgNWAbMDHgH9Ax0B/QNSAaUDFAEbYAADFQEcA1MBpwMuAfkDIQH7A0kBhiQAA0kBhgMhAfsDLgH5A1MB
|
||||||
|
pwMVARwIAAMPARMDQwF2A1wB2QMfAf0DAAH/AwAB/wNVAa8DFgEdRAADPwFsAy4B+QNTAacDFQEcBAAD
|
||||||
|
DwEUA1cBuQMAAf8DWAHtAz8BbQM/AW0DWAHtAwAB/wNXAbkDDwEUBAADFQEcA1MBpwMuAfkDPwFsIAAD
|
||||||
|
FAEbA1IBpQMdAf0DVQG0AyYBOAMHAQk4AAMWAR4DVgGzAx4B/QMdAf0DUgGlAxQBG2AAAwIBAwMeASoD
|
||||||
|
VQG0Az0B9wNSAaADGwElAwUBBhwAA0kBhgMhAfsDLgH5A1MBpwMVARwIAAQCAwkBCwMYASADRAF6A2AB
|
||||||
|
2wM7AfcDPQH3A1kBuwMqAUADDgESAwUBBgQCNAADPwFsAy4B+QNTAacDFQEcBAADDwEUA1cBuQMAAf8D
|
||||||
|
WAHtAz8BbQM/AW0DWAHtAwAB/wNXAbkDDwEUBAADFQEcA1MBpwMuAfkDPwFsIAADFAEbA1IBpQMdAf0D
|
||||||
|
VQG0AyYBOAMHAQk4AAMWAR4DVgGzAx4B/QMdAf0DUgGlAxQBG2QAAw8BEwNAAW8DXQHUA1MB7wNMAZED
|
||||||
|
EgEYHAADSQGGAyEB+wMuAfkDUwGnAxUBHBAABAIDDQERAzYBVwNYAbcDWwHsA1UB8QNdAdEDRAF5AzMB
|
||||||
|
UAMbASYDBgEHMAADPwFsAy4B+QNTAacDFQEcBAADDwEUA1cBuQMAAf8DWAHtAz8BbQM/AW0DWAHtAwAB
|
||||||
|
/wNXAbkDDwEUBAADFQEcA1MBpwMuAfkDPwFsIAADFAEbA1IBpQMdAf0DVQG0AyYBOAMHAQk4AAMWAR4D
|
||||||
|
VgGzAx4B/QMdAf0DUgGlAxQBG2QAAwIBAwMPARMDUQGeAx0B/QNSAaUDFAEbHAADSQGGAyEB+wMuAfkD
|
||||||
|
UwGnAxUBHBgAAwsBDgMtAUQDSwGPA1sBxQNhAeEDYQHhA1sBzQNMAZADKAE7AwkBDCwAAz8BbAMuAfkD
|
||||||
|
UwGnAxUBHAQAAw8BFANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUBHANTAacD
|
||||||
|
LgH5Az8BbCAAAxQBGwNSAaUDHQH9A1UBtAMmATgDBwEJOAADFgEeA1YBswMeAf0DHQH9A1IBpQMUARts
|
||||||
|
AANNAZMDHQH9A1IBpQMUARscAANJAYYDIQH7Ay4B+QNTAacDFQEcHAADBgEIAxkBIgMvAUkDQAFxA10B
|
||||||
|
zANNAfMDWgHpA1YBtgMtAUQsAAM/AWwDLgH5A1MBpwMVARwEAAMPARQDVwG5AwAB/wNYAe0DPwFtAz8B
|
||||||
|
bQNYAe0DAAH/A1cBuQMPARQEAAMVARwDUwGnAy4B+QM/AWwgAAMUARsDUgGlAx0B/QNVAbQDJgE4AwcB
|
||||||
|
CTgAAxYBHgNWAbMDHgH9Ax0B/QNSAaUDFAEbbAADTQGTAx0B/QNSAaUDFAEbHAADSQGGAyEB+wMuAfkD
|
||||||
|
UwGnAxUBHCAABAIDBAEFAwsBDgMwAUwDWQHBAzoB9gMsAfkDQQFyAwYBCCgAAz8BbAMuAfkDUwGnAxUB
|
||||||
|
HAQAAw8BFANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUBHANTAacDLgH5Az8B
|
||||||
|
bCAAAxQBGwNSAaUDHQH9A1UBtAMmATgDBwEJOAADFgEeA1YBswMeAf0DHQH9A1IBpQMUARtsAANNAZMD
|
||||||
|
HQH9A1IBpQMUARscAANJAYYDIQH7Ay4B+QNTAacDFQEcMAADFQEcA1MBpwMuAfkDWwHTAzoBYSgAAz8B
|
||||||
|
bAMuAfkDUwGnAxUBHAQAAw8BFANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUB
|
||||||
|
HANTAacDLgH5Az8BbCAAAxQBGwNSAaUDHQH9A1UBtAMmATgDBwEJOAADFgEeA1YBswMeAf0DHQH9A1IB
|
||||||
|
pQMUARsQAAQBAwQBBQMLAQ4DDwETAw8BEwMPARMDDwETAw8BEwMNAREDCQEMAwMBBAQBLAADTQGTAx0B
|
||||||
|
/QNSAaUDFAEbHAADSQGGAyEB+wMuAfkDUwGnAxUBHCAABAEDAgEDAwsBDgMwAUwDWQHBAzoB9gMsAfkD
|
||||||
|
QQFyAwYBCCgAAz8BbAMuAfkDUwGnAxUBHAQAAw8BFANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8D
|
||||||
|
VwG5Aw8BFAQAAxUBHANTAacDLgH5Az8BbCAAAxQBGwNSAaUDHQH9A1UBtAMmATgDBwEJOAADFgEeA1YB
|
||||||
|
swMeAf0DHQH9A1IBpQMUARsQAAMGAQgDJAE1Az4BawNGAX0DRgF+A0YBfgNGAX4DRgF+A0QBewM9AWkD
|
||||||
|
JAE0AwkBDCwAA00BkwMdAf0DUgGlAxQBGxwAA0kBhgMhAfsDLgH5A1MBpwMVARwcAAMGAQgDEgEXAyMB
|
||||||
|
MwM/AW4DWwHNAzoB9gNYAeoDVgG2Ay0BRCwAAz8BbAMuAfkDUwGnAxUBHAQAAw8BFANXAbkDAAH/A1gB
|
||||||
|
7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUBHANTAacDLgH5Az8BbCAAAxQBGwNSAaUDHQH9A1UB
|
||||||
|
tAMmATgDBwEJOAADFgEeA1YBswMeAf0DHQH9A1IBpQMUARsQAAMQARUDRgF/A1wB2QNYAeoDXgHmA2EB
|
||||||
|
4QNgAeADXgHiA1wB5wNhAeEDUAGdAyEBMCQAAwIBAwMPARMDUQGeAx0B/QNSAaUDFAEbHAADSQGGAyEB
|
||||||
|
+wMuAfkDUwGnAxUBHBgAAwsBDgMtAUQDRgGBA1MBqQNdAd8DXQHoA18B2gNOAZYDKAE8AwkBDCwAAz8B
|
||||||
|
bAMuAfkDUwGnAxUBHAQAAw8BFANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUB
|
||||||
|
HANTAacDLgH5Az8BbCAAAxQBGwNSAaUDHQH9A1UBtAMmATgDBwEJOAADFgEeA1YBswMeAf0DHQH9A1IB
|
||||||
|
pQMUARsQAAMTARoDTgGYA0IB9QMAAf8DYAHgA1YBtgNZAb4DXgHXAz0B9wMgAfwDWgHHAysBQiQAAw8B
|
||||||
|
EwNAAW8DXQHUA1MB7wNNAZIDEgEYHAADSQGGAyEB+wMuAfkDUwGnAxUBHBAABAIDDQERAzYBVwNYAbcD
|
||||||
|
WAHqA1wB7ANfAdUDSwGPAzoBYAMeASsDBgEHMAADPwFsAy4B+QNTAacDFQEcBAADDwEUA1cBuQMAAf8D
|
||||||
|
WAHtAz8BbQM/AW0DWAHtAwAB/wNXAbkDDwEUBAADFQEcA1MBpwMuAfkDPwFsIAADFAEbA1IBpQMdAf0D
|
||||||
|
VQG0AyYBOAMHAQk4AAMWAR4DVgGzAx4B/QMdAf0DUgGlAxQBGxAAAxQBGwNQAZoDOQH2AwAB/wNRAaQD
|
||||||
|
JAE0A0QBeANeAd0DPQH3A1sB3gM7AWMDDgESIAADAgEDAx4BKgNVAbQDPQH3A1EBoQMbASYDBQEGHAAD
|
||||||
|
SQGGAyEB+wMuAfkDUwGnAxUBHAwABAEDEwEZA0QBegNgAdsDOwH3Az0B9wNZAbsDKwFCAxMBGQMIAQoD
|
||||||
|
AgEDNAADPwFsAy4B+QNTAacDFQEcBAADDwEUA1cBuQMAAf8DWAHtAz8BbQM/AW0DWAHtAwAB/wNXAbkD
|
||||||
|
DwEUBAADFQEcA1MBpwMuAfkDPwFsIAADFAEbA1IBpQMdAf0DVQG0AyYBOAMHAQk4AAMWAR4DVgGzAx4B
|
||||||
|
/QMdAf0DUgGlAxQBGxAAAxQBGwNQAZoDOQH2AwAB/wNOAZUDMQFMA2EB4QMAAf8DWwHNAxoBJCgAAxUB
|
||||||
|
HANTAacDLgH5AyEB+wNJAYYkAANJAYYDIQH7Ay4B+QNTAacDFQEcDAADCwEOA00BkgMrAfkDAAH/AwAB
|
||||||
|
/wNVAa8DFgEdRAADPwFsAy4B+QNTAacDFQEcBAADDwEUA1cBuQMAAf8DWAHtAz8BbQM/AW0DWAHtAwAB
|
||||||
|
/wNXAbkDDwEUBAADFQEcA1MBpwMuAfkDPwFsIAADFAEbA1IBpQMdAf0DVgG2AygBPAMIAQo4AAMWAR4D
|
||||||
|
VgGzAx4B/QMdAf0DUgGlAxQBGxAAAxQBGwNQAZoDOQH2AwAB/wNDAfUDVAHvAyEB/AMRAf4DXQHMAx0B
|
||||||
|
KQQCGAAEAgMGAQcDDwETAzIBTwNZAcADQgH1A10B0QM6AWAkAANJAYYDIQH7Ay4B+QNTAacDFgEeAwwB
|
||||||
|
EAMqAUADVwG5A1oB6QNTAe8DWwHoA10BzwNGAX0DEwEaAwIBA0QAAz8BbAMuAfkDUwGnAxUBHAQAAw8B
|
||||||
|
FANXAbkDAAH/A1gB7QM/AW0DPwFtA1gB7QMAAf8DVwG5Aw8BFAQAAxUBHANTAacDLgH5Az8BbCAAAxQB
|
||||||
|
GwNSAaUDHQH9A1sB0AM/AWwDGAEhAw4BEgMOARIDDgESAw4BEgMOARIDDgESAw4BEgMOARIDDgESAw4B
|
||||||
|
EgMOARIDDgESAw4BEgMOARIDIAEuA1cBuQMeAf0DHQH9A1IBpQMUARsQAAMUARsDUAGaAzkB9gMAAf8D
|
||||||
|
AAH/AyMB+gNCAfUDHgH9A2AB4ANAAXEDHQEoAw4BEgMNAREDCQEMAwgBCgMLBA4BEgMcAScDOAFbA0QB
|
||||||
|
eQNaAccDYQHhA1YBtgM0AVQDDAEPJAADSQGGAyEB+wMuAfkDVQGuAyoBQAM/AW0DXQHRA0MB9QNWAe4D
|
||||||
|
WQG7A0QBeQMqAUADEQEWBAJIAAM/AWwDLgH5A1UBrgMgAS0DDgESAxsBJQNZAb4DAAH/A1gB7QM/AW0D
|
||||||
|
PwFtA1gB7QMAAf8DWQG+AxsBJQMOARIDIAEtA1UBrgMuAfkDPwFsIAADEwEaA1EBpAMfAfwDOQH2A10B
|
||||||
|
zANLAY0DRgGAA0YBgANGAYADRgGAA0YBgANGAYADRgGAA0YBgANGAYADRgGAA0YBgANGAYADRgGAA0YB
|
||||||
|
gANLAY8DXAHZAx4B/QNFAfQDTgGYAxMBGRAAAxIBGANLAYwDWAHtAwAB/wMgAf0DXAHZA1UBsQNdAd8D
|
||||||
|
QwH1A2AB4ANPAZsDRgGAA0QBegM5AV4DMwFQAz0BaANGAX4DUAGaA18B2gNbAeQDXwHaA08BmwMpAT4D
|
||||||
|
CgENKAADSQGGAyEB+wMgAfwDWwHTA1MBpgNcAdkDLgH5A2AB4ANQAZoDLQFFAxABFQMGAQcEAUwAAz8B
|
||||||
|
bAMgAfwDWwHTA0wBjgNGAYADSgGKA10B3AMeAf0DXQHfAzoBYgM6AWIDXQHfAx4B/QNdAdwDSgGKA0YB
|
||||||
|
gANMAY4DWwHTAyAB/AM/AWwgAAMSARcDSgGLA1oB6gMPAf4DJAH6A1IB7wNYAe0DWAHtA1gB7QNYAe0D
|
||||||
|
WAHtA1gB7QNYAe0DWAHtA1gB7QNYAe0DWAHtA1gB7QNYAe0DWAHtA1IB7wMkAfoDHgH9A1cBwgM0AVQD
|
||||||
|
CwEOEAADCAEKAy4BSANVAbEDXgHiA2AB2wNPAZsDLQFEA0MBdwNdAcwDYQHhA1gB6gNYAe0DWgHpA1sB
|
||||||
|
0wNcAcgDXwHaA1wB6wNOAfIDLgH5A14B0gNEAXgDIQEvAwcBCSwAA0IBdQNYAeoDAQH/Ay4B+QNQAfAD
|
||||||
|
XAHsA1wB2QNEAXsDHgEqAwYBCFgAAz8BbAMBAf8DLgH5A1IB7wNYAe0DVgHuAyQB+gM5AfYDUAGdAyAB
|
||||||
|
LQMgAS0DUAGdAzkB9gMkAfoDVgHuA1gB7QNSAe8DLgH5Aw8B/gM/AWwgAAMFAQYDGgEjA00BkwNgAeYD
|
||||||
|
WgHtAzwB9gM9AfcDPQH3Az0B9wM9AfcDPQH3Az0B9wM9AfcDPQH3Az0B9wM9AfcDPQH3Az0B9wM9AfcD
|
||||||
|
PQH3AzwB9gNaAe0DXwHlA0cBgwMKAQ0EAhAABAEDCAEKAx8BLAMuAUgDLQFEAxsBJQMHAQkDDwETAyMB
|
||||||
|
MgMuAUcDVwG5A10B6ANaAekDVwHuA1UB8QNcAewDWgHpA10B6ANbAdADNAFTAw8BEwMCAQMwAAMWAR4D
|
||||||
|
RwGDA1oB7QNVAfEDXwHVA0wBjgMrAUIDDwEUBAJcAAM6AWIDWgHpA1oB7QM8AfYDPQH3AzwB9gNcAewD
|
||||||
|
XQHcAzwBZgMGAQgDBgEIAzwBZgNdAdwDWgHtAzwB9gM9AfcDPAH2A1oB7QNgAeYDOgFiLAAEAQMjATMD
|
||||||
|
TgGXA1QBqwNUAasDVAGrA1QBqwNUAasDVAGrA1QBqwNUAasDVAGrA1QBqwNUAasDVAGrA1QBqwNUAasD
|
||||||
|
TgGXAyMBMwQBTAADCQELAzkBXQNHAYIDJwE6AwQBBUgABAIDIgExAzoBYQMPARRwAAMDAQQDKAE7A04B
|
||||||
|
mANUAasDUQGeAyEBLxQAAwMBBAMlATcDUAGfA1QBqwNOAZgDKAE7AwMBBBgAAUIBTQE+BwABPgMAASgD
|
||||||
|
AAF8AwABMAMAAQEBAAEBBgABAxYAA/8BAAH8AQMB8AE/AQMB8AEPAcAIAAH8AQEB8AE/AQMB8AEHAcAI
|
||||||
|
AAH8AQABMAE/AQAB8AEDAYAIAAH8AQABEAE/AQABcAEAAYAIAAH8AgABPwEAATABAAGACAAB/AIAAT8B
|
||||||
|
AAEwAQABgAgAAfwCAAE/DAAB/AEIAQABPwEICwAB/AEMAQABPwEMAQABIAkAAfwBDwEAAT8BDAEAATAJ
|
||||||
|
AAH8AQ8BgAE/AQ4BAAE4CQAB/AEPAfABPwEPAcABPwkAAfwBDwGAAT8BDgEAATgJAAH8AQ8BAAE/AQwB
|
||||||
|
AAEwCQAB/AEMAQABPwEMAQABIAkAAfwBCAEAAT8BCAsAAfwCAAE/DAAB/AIAAT8BAAEwCgAB/AIAAT8B
|
||||||
|
AAEwAQABgAgAAfwBAAEQAT8BAAFwAQABgAgAAfwBAAEwAT8BAAHwAQMBgAgAAfwBAAHwAT8BAQHwAQcB
|
||||||
|
wAgAAfwBAwHwAT8BAwHwAQ8BwAgAAf4BHwH4AX8BDwH4AX8BwAgAAeACAAEHAf4BAAEBAf8B4AEPAv8B
|
||||||
|
4AEAAQEB8AHgAgABBwH8AgAB/wHgAQcC/wHgAQABAQHwAeACAAEHAfwCAAF/AeABAwL/AeABAAEBAfAB
|
||||||
|
4AIAAQcB/AIAAT8B4AEAAX8B/wHgAQABAQHwAeABfwH+AQcB/AEHAcABPwHgAQABPwH/AeEBAAEhAfAB
|
||||||
|
4AF/Af4BBwL/AfgBPwHgAcABPwH/AeEBAAEhAfAB4AF/Af4BBwL/AfgBDwHgAcABAwH/AeEBAAEhAfAB
|
||||||
|
4AF/Af4BBwL/AfwBDwHgAfABAQH/AeEBAAEhAfAB4AF/Af4BBwL/AfwBDwHgAfwBAAH/AeEBAAEhAfAB
|
||||||
|
4AF/Af4BBwP/AQ8B4AH+AQAB/wHhAQABIQHwAeABfwH+AQcD/wEPAeAB/wEAAX8B4QEAASEB8AHgAX8B
|
||||||
|
/gEHA/8BDwHgAf8B8AF/AeEBAAEhAfAB4AF/Af4BBwGAAQcB/wEPAeAB/wEAAX8B4QEAASEB8AHgAX8B
|
||||||
|
/gEHAYABBwH/AQ8B4AH+AQAB/wHhAQABIQHwAeABfwH+AQcBgAEHAfwBDwHgAfwBAAH/AeEBAAEhAfAB
|
||||||
|
4AF/Af4BBwGAAQcB/AEPAeAB8AEBAf8B4QEAASEB8AHgAX8B/gEHAYABBwH4AQ8C4AEDAf8B4QEAASEB
|
||||||
|
8AHgAX8B/gEHAYABHwH4AT8C4AE/Af8B4QEAASEB8AHgAX8B/gEHAYABDwHAAT8B4AEAAT8B/wHhAQAB
|
||||||
|
IQHwAeACAAEHAYACAAE/AeABAAF/Af8B4AEAAQEB8AHgAgABBwGAAgABfwHgAQAC/wHgAQABAQHwAeAC
|
||||||
|
AAEHAYACAAH/AeABBwL/AeABAAEBAfAB4AIAAQcBgAEAAQEB/wHgAQ8C/wHgAQABAQHwAfwCAAE/Af8B
|
||||||
|
+AE/Af8B8AP/AfABPgEDAfAL
|
||||||
|
</value>
|
||||||
|
</data>
|
||||||
|
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>165, 17</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
98
SpineViewer/Dialogs/BatchOpenSpineDialog.Designer.cs
generated
98
SpineViewer/Dialogs/BatchOpenSpineDialog.Designer.cs
generated
@@ -37,10 +37,7 @@
|
|||||||
tableLayoutPanel2 = new TableLayoutPanel();
|
tableLayoutPanel2 = new TableLayoutPanel();
|
||||||
button_Ok = new Button();
|
button_Ok = new Button();
|
||||||
button_Cancel = new Button();
|
button_Cancel = new Button();
|
||||||
listBox_FilePath = new ListBox();
|
skelFileListBox = new SpineViewer.Controls.SkelFileListBox();
|
||||||
button_SelectSkel = new Button();
|
|
||||||
label_Tip = new Label();
|
|
||||||
openFileDialog_Skel = new OpenFileDialog();
|
|
||||||
panel.SuspendLayout();
|
panel.SuspendLayout();
|
||||||
tableLayoutPanel1.SuspendLayout();
|
tableLayoutPanel1.SuspendLayout();
|
||||||
tableLayoutPanel2.SuspendLayout();
|
tableLayoutPanel2.SuspendLayout();
|
||||||
@@ -53,7 +50,7 @@
|
|||||||
panel.Location = new Point(0, 0);
|
panel.Location = new Point(0, 0);
|
||||||
panel.Name = "panel";
|
panel.Name = "panel";
|
||||||
panel.Padding = new Padding(50, 15, 50, 10);
|
panel.Padding = new Padding(50, 15, 50, 10);
|
||||||
panel.Size = new Size(1126, 449);
|
panel.Size = new Size(1042, 472);
|
||||||
panel.TabIndex = 1;
|
panel.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// tableLayoutPanel1
|
// tableLayoutPanel1
|
||||||
@@ -62,22 +59,19 @@
|
|||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
||||||
tableLayoutPanel1.Controls.Add(label3, 0, 3);
|
tableLayoutPanel1.Controls.Add(label3, 0, 2);
|
||||||
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 3);
|
tableLayoutPanel1.Controls.Add(comboBox_Version, 1, 2);
|
||||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 4);
|
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 3);
|
||||||
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
|
tableLayoutPanel1.Controls.Add(skelFileListBox, 0, 1);
|
||||||
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
|
|
||||||
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
|
|
||||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||||
tableLayoutPanel1.Location = new Point(50, 15);
|
tableLayoutPanel1.Location = new Point(50, 15);
|
||||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
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(942, 447);
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.Size = new Size(1026, 424);
|
|
||||||
tableLayoutPanel1.TabIndex = 1;
|
tableLayoutPanel1.TabIndex = 1;
|
||||||
//
|
//
|
||||||
// label4
|
// label4
|
||||||
@@ -88,7 +82,7 @@
|
|||||||
label4.Location = new Point(15, 15);
|
label4.Location = new Point(15, 15);
|
||||||
label4.Margin = new Padding(15);
|
label4.Margin = new Padding(15);
|
||||||
label4.Name = "label4";
|
label4.Name = "label4";
|
||||||
label4.Size = new Size(996, 24);
|
label4.Size = new Size(912, 24);
|
||||||
label4.TabIndex = 14;
|
label4.TabIndex = 14;
|
||||||
label4.Text = "说明:批量导入只需要选择skel文件,atlas文件需要在同目录下并且与skel文件名相同";
|
label4.Text = "说明:批量导入只需要选择skel文件,atlas文件需要在同目录下并且与skel文件名相同";
|
||||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
label4.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
@@ -97,7 +91,7 @@
|
|||||||
//
|
//
|
||||||
label3.Anchor = AnchorStyles.Right;
|
label3.Anchor = AnchorStyles.Right;
|
||||||
label3.AutoSize = true;
|
label3.AutoSize = true;
|
||||||
label3.Location = new Point(90, 307);
|
label3.Location = new Point(3, 343);
|
||||||
label3.Name = "label3";
|
label3.Name = "label3";
|
||||||
label3.Size = new Size(50, 24);
|
label3.Size = new Size(50, 24);
|
||||||
label3.TabIndex = 12;
|
label3.TabIndex = 12;
|
||||||
@@ -108,7 +102,7 @@
|
|||||||
comboBox_Version.Anchor = AnchorStyles.Left;
|
comboBox_Version.Anchor = AnchorStyles.Left;
|
||||||
comboBox_Version.DropDownStyle = ComboBoxStyle.DropDownList;
|
comboBox_Version.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||||
comboBox_Version.FormattingEnabled = true;
|
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.Name = "comboBox_Version";
|
||||||
comboBox_Version.Size = new Size(182, 32);
|
comboBox_Version.Size = new Size(182, 32);
|
||||||
comboBox_Version.Sorted = true;
|
comboBox_Version.Sorted = true;
|
||||||
@@ -124,18 +118,19 @@
|
|||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
tableLayoutPanel2.Dock = DockStyle.Fill;
|
||||||
tableLayoutPanel2.Location = new Point(3, 381);
|
tableLayoutPanel2.Location = new Point(3, 404);
|
||||||
|
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||||
tableLayoutPanel2.RowCount = 1;
|
tableLayoutPanel2.RowCount = 1;
|
||||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||||
tableLayoutPanel2.Size = new Size(1020, 40);
|
tableLayoutPanel2.Size = new Size(936, 40);
|
||||||
tableLayoutPanel2.TabIndex = 11;
|
tableLayoutPanel2.TabIndex = 11;
|
||||||
//
|
//
|
||||||
// button_Ok
|
// button_Ok
|
||||||
//
|
//
|
||||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
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.Margin = new Padding(3, 3, 30, 3);
|
||||||
button_Ok.Name = "button_Ok";
|
button_Ok.Name = "button_Ok";
|
||||||
button_Ok.Size = new Size(112, 34);
|
button_Ok.Size = new Size(112, 34);
|
||||||
@@ -147,7 +142,7 @@
|
|||||||
// button_Cancel
|
// button_Cancel
|
||||||
//
|
//
|
||||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
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.Margin = new Padding(30, 3, 3, 3);
|
||||||
button_Cancel.Name = "button_Cancel";
|
button_Cancel.Name = "button_Cancel";
|
||||||
button_Cancel.Size = new Size(112, 34);
|
button_Cancel.Size = new Size(112, 34);
|
||||||
@@ -156,47 +151,14 @@
|
|||||||
button_Cancel.UseVisualStyleBackColor = true;
|
button_Cancel.UseVisualStyleBackColor = true;
|
||||||
button_Cancel.Click += button_Cancel_Click;
|
button_Cancel.Click += button_Cancel_Click;
|
||||||
//
|
//
|
||||||
// listBox_FilePath
|
// skelFileListBox
|
||||||
//
|
//
|
||||||
tableLayoutPanel1.SetColumnSpan(listBox_FilePath, 2);
|
tableLayoutPanel1.SetColumnSpan(skelFileListBox, 2);
|
||||||
listBox_FilePath.Dock = DockStyle.Fill;
|
skelFileListBox.Dock = DockStyle.Fill;
|
||||||
listBox_FilePath.FormattingEnabled = true;
|
skelFileListBox.Location = new Point(3, 57);
|
||||||
listBox_FilePath.HorizontalScrollbar = true;
|
skelFileListBox.Name = "skelFileListBox";
|
||||||
listBox_FilePath.ItemHeight = 24;
|
skelFileListBox.Size = new Size(936, 276);
|
||||||
listBox_FilePath.Location = new Point(3, 97);
|
skelFileListBox.TabIndex = 15;
|
||||||
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文件";
|
|
||||||
//
|
//
|
||||||
// BatchOpenSpineDialog
|
// BatchOpenSpineDialog
|
||||||
//
|
//
|
||||||
@@ -204,7 +166,7 @@
|
|||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
CancelButton = button_Cancel;
|
CancelButton = button_Cancel;
|
||||||
ClientSize = new Size(1126, 449);
|
ClientSize = new Size(1042, 472);
|
||||||
Controls.Add(panel);
|
Controls.Add(panel);
|
||||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||||
@@ -214,7 +176,6 @@
|
|||||||
ShowInTaskbar = false;
|
ShowInTaskbar = false;
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
Text = "批量打开骨骼";
|
Text = "批量打开骨骼";
|
||||||
Load += BatchOpenSpineDialog_Load;
|
|
||||||
panel.ResumeLayout(false);
|
panel.ResumeLayout(false);
|
||||||
tableLayoutPanel1.ResumeLayout(false);
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
tableLayoutPanel1.PerformLayout();
|
tableLayoutPanel1.PerformLayout();
|
||||||
@@ -225,15 +186,12 @@
|
|||||||
#endregion
|
#endregion
|
||||||
private Panel panel;
|
private Panel panel;
|
||||||
private TableLayoutPanel tableLayoutPanel1;
|
private TableLayoutPanel tableLayoutPanel1;
|
||||||
private Label label_Tip;
|
|
||||||
private ListBox listBox_FilePath;
|
|
||||||
private Button button_SelectSkel;
|
|
||||||
private TableLayoutPanel tableLayoutPanel2;
|
private TableLayoutPanel tableLayoutPanel2;
|
||||||
private Button button_Ok;
|
private Button button_Ok;
|
||||||
private Button button_Cancel;
|
private Button button_Cancel;
|
||||||
private Label label3;
|
private Label label3;
|
||||||
private ComboBox comboBox_Version;
|
private ComboBox comboBox_Version;
|
||||||
private OpenFileDialog openFileDialog_Skel;
|
|
||||||
private Label label4;
|
private Label label4;
|
||||||
|
private Controls.SkelFileListBox skelFileListBox;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,33 +27,19 @@ namespace SpineViewer.Dialogs
|
|||||||
comboBox_Version.SelectedValue = Spine.Version.Auto;
|
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)
|
private void button_Ok_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var version = (Spine.Version)comboBox_Version.SelectedValue;
|
var version = (Spine.Version)comboBox_Version.SelectedValue;
|
||||||
|
|
||||||
if (listBox_FilePath.Items.Count <= 0)
|
var items = skelFileListBox.Items;
|
||||||
|
|
||||||
|
if (items.Count <= 0)
|
||||||
{
|
{
|
||||||
MessageBox.Info("未选择任何文件");
|
MessageBox.Info("未选择任何文件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string p in listBox_FilePath.Items)
|
foreach (string p in items)
|
||||||
{
|
{
|
||||||
if (!File.Exists(p))
|
if (!File.Exists(p))
|
||||||
{
|
{
|
||||||
@@ -68,7 +54,7 @@ namespace SpineViewer.Dialogs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result = new(version, listBox_FilePath.Items.Cast<string>().ToArray());
|
Result = new(version, items.Cast<string>().ToArray());
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</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" />
|
<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">
|
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<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));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ConvertFileFormatDialog));
|
||||||
panel = new Panel();
|
panel = new Panel();
|
||||||
tableLayoutPanel1 = new TableLayoutPanel();
|
tableLayoutPanel1 = new TableLayoutPanel();
|
||||||
|
comboBox_TargetVersion = new ComboBox();
|
||||||
flowLayoutPanel_TargetFormat = new FlowLayoutPanel();
|
flowLayoutPanel_TargetFormat = new FlowLayoutPanel();
|
||||||
radioButton_BinaryTarget = new RadioButton();
|
radioButton_BinaryTarget = new RadioButton();
|
||||||
radioButton_JsonTarget = new RadioButton();
|
radioButton_JsonTarget = new RadioButton();
|
||||||
@@ -41,19 +42,13 @@
|
|||||||
tableLayoutPanel2 = new TableLayoutPanel();
|
tableLayoutPanel2 = new TableLayoutPanel();
|
||||||
button_Ok = new Button();
|
button_Ok = new Button();
|
||||||
button_Cancel = new Button();
|
button_Cancel = new Button();
|
||||||
listBox_FilePath = new ListBox();
|
|
||||||
button_SelectSkel = new Button();
|
|
||||||
label_Tip = new Label();
|
|
||||||
label2 = new Label();
|
label2 = new Label();
|
||||||
flowLayoutPanel_SourceFormat = new FlowLayoutPanel();
|
skelFileListBox = new SpineViewer.Controls.SkelFileListBox();
|
||||||
radioButton_BinarySource = new RadioButton();
|
|
||||||
radioButton_JsonSource = new RadioButton();
|
|
||||||
openFileDialog_Skel = new OpenFileDialog();
|
openFileDialog_Skel = new OpenFileDialog();
|
||||||
panel.SuspendLayout();
|
panel.SuspendLayout();
|
||||||
tableLayoutPanel1.SuspendLayout();
|
tableLayoutPanel1.SuspendLayout();
|
||||||
flowLayoutPanel_TargetFormat.SuspendLayout();
|
flowLayoutPanel_TargetFormat.SuspendLayout();
|
||||||
tableLayoutPanel2.SuspendLayout();
|
tableLayoutPanel2.SuspendLayout();
|
||||||
flowLayoutPanel_SourceFormat.SuspendLayout();
|
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
//
|
//
|
||||||
// panel
|
// panel
|
||||||
@@ -63,7 +58,7 @@
|
|||||||
panel.Location = new Point(0, 0);
|
panel.Location = new Point(0, 0);
|
||||||
panel.Name = "panel";
|
panel.Name = "panel";
|
||||||
panel.Padding = new Padding(50, 15, 50, 10);
|
panel.Padding = new Padding(50, 15, 50, 10);
|
||||||
panel.Size = new Size(1039, 530);
|
panel.Size = new Size(1051, 538);
|
||||||
panel.TabIndex = 2;
|
panel.TabIndex = 2;
|
||||||
//
|
//
|
||||||
// tableLayoutPanel1
|
// tableLayoutPanel1
|
||||||
@@ -71,40 +66,48 @@
|
|||||||
tableLayoutPanel1.ColumnCount = 2;
|
tableLayoutPanel1.ColumnCount = 2;
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel_TargetFormat, 1, 5);
|
tableLayoutPanel1.Controls.Add(comboBox_TargetVersion, 1, 3);
|
||||||
tableLayoutPanel1.Controls.Add(label1, 0, 4);
|
tableLayoutPanel1.Controls.Add(flowLayoutPanel_TargetFormat, 1, 4);
|
||||||
|
tableLayoutPanel1.Controls.Add(label1, 0, 3);
|
||||||
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
tableLayoutPanel1.Controls.Add(label4, 0, 0);
|
||||||
tableLayoutPanel1.Controls.Add(label3, 0, 3);
|
tableLayoutPanel1.Controls.Add(label3, 0, 2);
|
||||||
tableLayoutPanel1.Controls.Add(comboBox_SourceVersion, 1, 3);
|
tableLayoutPanel1.Controls.Add(comboBox_SourceVersion, 1, 2);
|
||||||
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 6);
|
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 5);
|
||||||
tableLayoutPanel1.Controls.Add(listBox_FilePath, 0, 2);
|
tableLayoutPanel1.Controls.Add(label2, 0, 4);
|
||||||
tableLayoutPanel1.Controls.Add(button_SelectSkel, 0, 1);
|
tableLayoutPanel1.Controls.Add(skelFileListBox, 0, 1);
|
||||||
tableLayoutPanel1.Controls.Add(label_Tip, 1, 1);
|
|
||||||
tableLayoutPanel1.Controls.Add(label2, 0, 5);
|
|
||||||
tableLayoutPanel1.Controls.Add(flowLayoutPanel_SourceFormat, 1, 4);
|
|
||||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||||
tableLayoutPanel1.Location = new Point(50, 15);
|
tableLayoutPanel1.Location = new Point(50, 15);
|
||||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
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.RowStyles.Add(new RowStyle());
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
tableLayoutPanel1.Size = new Size(951, 513);
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel1.Size = new Size(939, 505);
|
|
||||||
tableLayoutPanel1.TabIndex = 1;
|
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
|
||||||
//
|
//
|
||||||
flowLayoutPanel_TargetFormat.AutoSize = true;
|
flowLayoutPanel_TargetFormat.AutoSize = true;
|
||||||
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_BinaryTarget);
|
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_BinaryTarget);
|
||||||
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_JsonTarget);
|
flowLayoutPanel_TargetFormat.Controls.Add(radioButton_JsonTarget);
|
||||||
flowLayoutPanel_TargetFormat.Dock = DockStyle.Fill;
|
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.Name = "flowLayoutPanel_TargetFormat";
|
||||||
flowLayoutPanel_TargetFormat.Size = new Size(790, 34);
|
flowLayoutPanel_TargetFormat.Size = new Size(853, 34);
|
||||||
flowLayoutPanel_TargetFormat.TabIndex = 19;
|
flowLayoutPanel_TargetFormat.TabIndex = 19;
|
||||||
//
|
//
|
||||||
// radioButton_BinaryTarget
|
// radioButton_BinaryTarget
|
||||||
@@ -116,7 +119,6 @@
|
|||||||
radioButton_BinaryTarget.TabIndex = 17;
|
radioButton_BinaryTarget.TabIndex = 17;
|
||||||
radioButton_BinaryTarget.Text = "二进制 (*.skel)";
|
radioButton_BinaryTarget.Text = "二进制 (*.skel)";
|
||||||
radioButton_BinaryTarget.UseVisualStyleBackColor = true;
|
radioButton_BinaryTarget.UseVisualStyleBackColor = true;
|
||||||
radioButton_BinaryTarget.CheckedChanged += radioButton_Target_CheckedChanged;
|
|
||||||
//
|
//
|
||||||
// radioButton_JsonTarget
|
// radioButton_JsonTarget
|
||||||
//
|
//
|
||||||
@@ -129,17 +131,16 @@
|
|||||||
radioButton_JsonTarget.TabStop = true;
|
radioButton_JsonTarget.TabStop = true;
|
||||||
radioButton_JsonTarget.Text = "文本 (*.json)";
|
radioButton_JsonTarget.Text = "文本 (*.json)";
|
||||||
radioButton_JsonTarget.UseVisualStyleBackColor = true;
|
radioButton_JsonTarget.UseVisualStyleBackColor = true;
|
||||||
radioButton_JsonTarget.CheckedChanged += radioButton_Target_CheckedChanged;
|
|
||||||
//
|
//
|
||||||
// label1
|
// label1
|
||||||
//
|
//
|
||||||
label1.Anchor = AnchorStyles.Right;
|
label1.Anchor = AnchorStyles.Right;
|
||||||
label1.AutoSize = true;
|
label1.AutoSize = true;
|
||||||
label1.Location = new Point(72, 346);
|
label1.Location = new Point(3, 369);
|
||||||
label1.Name = "label1";
|
label1.Name = "label1";
|
||||||
label1.Size = new Size(68, 24);
|
label1.Size = new Size(86, 24);
|
||||||
label1.TabIndex = 15;
|
label1.TabIndex = 15;
|
||||||
label1.Text = "源格式:";
|
label1.Text = "目标版本:";
|
||||||
//
|
//
|
||||||
// label4
|
// label4
|
||||||
//
|
//
|
||||||
@@ -149,7 +150,7 @@
|
|||||||
label4.Location = new Point(15, 15);
|
label4.Location = new Point(15, 15);
|
||||||
label4.Margin = new Padding(15);
|
label4.Margin = new Padding(15);
|
||||||
label4.Name = "label4";
|
label4.Name = "label4";
|
||||||
label4.Size = new Size(909, 24);
|
label4.Size = new Size(921, 24);
|
||||||
label4.TabIndex = 14;
|
label4.TabIndex = 14;
|
||||||
label4.Text = "说明:将在每个文件同级目录下生成目标格式后缀的文件,会覆盖已存在文件";
|
label4.Text = "说明:将在每个文件同级目录下生成目标格式后缀的文件,会覆盖已存在文件";
|
||||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
label4.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
@@ -158,19 +159,19 @@
|
|||||||
//
|
//
|
||||||
label3.Anchor = AnchorStyles.Right;
|
label3.Anchor = AnchorStyles.Right;
|
||||||
label3.AutoSize = true;
|
label3.AutoSize = true;
|
||||||
label3.Location = new Point(72, 307);
|
label3.Location = new Point(21, 331);
|
||||||
label3.Name = "label3";
|
label3.Name = "label3";
|
||||||
label3.Size = new Size(68, 24);
|
label3.Size = new Size(68, 24);
|
||||||
label3.TabIndex = 12;
|
label3.TabIndex = 12;
|
||||||
label3.Text = "源版本:";
|
label3.Text = "源版本:";
|
||||||
//
|
//
|
||||||
// comboBox_Version
|
// comboBox_SourceVersion
|
||||||
//
|
//
|
||||||
comboBox_SourceVersion.Anchor = AnchorStyles.Left;
|
comboBox_SourceVersion.Anchor = AnchorStyles.Left;
|
||||||
comboBox_SourceVersion.DropDownStyle = ComboBoxStyle.DropDownList;
|
comboBox_SourceVersion.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||||
comboBox_SourceVersion.FormattingEnabled = true;
|
comboBox_SourceVersion.FormattingEnabled = true;
|
||||||
comboBox_SourceVersion.Location = new Point(146, 303);
|
comboBox_SourceVersion.Location = new Point(95, 327);
|
||||||
comboBox_SourceVersion.Name = "comboBox_Version";
|
comboBox_SourceVersion.Name = "comboBox_SourceVersion";
|
||||||
comboBox_SourceVersion.Size = new Size(182, 32);
|
comboBox_SourceVersion.Size = new Size(182, 32);
|
||||||
comboBox_SourceVersion.Sorted = true;
|
comboBox_SourceVersion.Sorted = true;
|
||||||
comboBox_SourceVersion.TabIndex = 13;
|
comboBox_SourceVersion.TabIndex = 13;
|
||||||
@@ -185,18 +186,19 @@
|
|||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
tableLayoutPanel2.Controls.Add(button_Ok, 0, 0);
|
||||||
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
tableLayoutPanel2.Controls.Add(button_Cancel, 1, 0);
|
||||||
tableLayoutPanel2.Dock = DockStyle.Bottom;
|
tableLayoutPanel2.Dock = DockStyle.Fill;
|
||||||
tableLayoutPanel2.Location = new Point(3, 462);
|
tableLayoutPanel2.Location = new Point(3, 470);
|
||||||
|
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||||
tableLayoutPanel2.RowCount = 1;
|
tableLayoutPanel2.RowCount = 1;
|
||||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||||
tableLayoutPanel2.Size = new Size(933, 40);
|
tableLayoutPanel2.Size = new Size(945, 40);
|
||||||
tableLayoutPanel2.TabIndex = 11;
|
tableLayoutPanel2.TabIndex = 11;
|
||||||
//
|
//
|
||||||
// button_Ok
|
// button_Ok
|
||||||
//
|
//
|
||||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
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.Margin = new Padding(3, 3, 30, 3);
|
||||||
button_Ok.Name = "button_Ok";
|
button_Ok.Name = "button_Ok";
|
||||||
button_Ok.Size = new Size(112, 34);
|
button_Ok.Size = new Size(112, 34);
|
||||||
@@ -208,7 +210,7 @@
|
|||||||
// button_Cancel
|
// button_Cancel
|
||||||
//
|
//
|
||||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
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.Margin = new Padding(30, 3, 3, 3);
|
||||||
button_Cancel.Name = "button_Cancel";
|
button_Cancel.Name = "button_Cancel";
|
||||||
button_Cancel.Size = new Size(112, 34);
|
button_Cancel.Size = new Size(112, 34);
|
||||||
@@ -217,84 +219,24 @@
|
|||||||
button_Cancel.UseVisualStyleBackColor = true;
|
button_Cancel.UseVisualStyleBackColor = true;
|
||||||
button_Cancel.Click += button_Cancel_Click;
|
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
|
||||||
//
|
//
|
||||||
label2.Anchor = AnchorStyles.Right;
|
label2.Anchor = AnchorStyles.Right;
|
||||||
label2.AutoSize = true;
|
label2.AutoSize = true;
|
||||||
label2.Location = new Point(54, 386);
|
label2.Location = new Point(3, 408);
|
||||||
label2.Name = "label2";
|
label2.Name = "label2";
|
||||||
label2.Size = new Size(86, 24);
|
label2.Size = new Size(86, 24);
|
||||||
label2.TabIndex = 16;
|
label2.TabIndex = 16;
|
||||||
label2.Text = "目标格式:";
|
label2.Text = "目标格式:";
|
||||||
//
|
//
|
||||||
// flowLayoutPanel_SourceFormat
|
// skelFileListBox
|
||||||
//
|
//
|
||||||
flowLayoutPanel_SourceFormat.AutoSize = true;
|
tableLayoutPanel1.SetColumnSpan(skelFileListBox, 2);
|
||||||
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_BinarySource);
|
skelFileListBox.Dock = DockStyle.Fill;
|
||||||
flowLayoutPanel_SourceFormat.Controls.Add(radioButton_JsonSource);
|
skelFileListBox.Location = new Point(3, 57);
|
||||||
flowLayoutPanel_SourceFormat.Dock = DockStyle.Fill;
|
skelFileListBox.Name = "skelFileListBox";
|
||||||
flowLayoutPanel_SourceFormat.Location = new Point(146, 341);
|
skelFileListBox.Size = new Size(945, 264);
|
||||||
flowLayoutPanel_SourceFormat.Name = "flowLayoutPanel_SourceFormat";
|
skelFileListBox.TabIndex = 20;
|
||||||
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;
|
|
||||||
//
|
//
|
||||||
// openFileDialog_Skel
|
// openFileDialog_Skel
|
||||||
//
|
//
|
||||||
@@ -310,7 +252,7 @@
|
|||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
CancelButton = button_Cancel;
|
CancelButton = button_Cancel;
|
||||||
ClientSize = new Size(1039, 530);
|
ClientSize = new Size(1051, 538);
|
||||||
Controls.Add(panel);
|
Controls.Add(panel);
|
||||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||||
@@ -320,15 +262,12 @@
|
|||||||
ShowInTaskbar = false;
|
ShowInTaskbar = false;
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
Text = "骨骼文件格式转换";
|
Text = "骨骼文件格式转换";
|
||||||
Load += ConvertFileFormatDialog_Load;
|
|
||||||
panel.ResumeLayout(false);
|
panel.ResumeLayout(false);
|
||||||
tableLayoutPanel1.ResumeLayout(false);
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
tableLayoutPanel1.PerformLayout();
|
tableLayoutPanel1.PerformLayout();
|
||||||
flowLayoutPanel_TargetFormat.ResumeLayout(false);
|
flowLayoutPanel_TargetFormat.ResumeLayout(false);
|
||||||
flowLayoutPanel_TargetFormat.PerformLayout();
|
flowLayoutPanel_TargetFormat.PerformLayout();
|
||||||
tableLayoutPanel2.ResumeLayout(false);
|
tableLayoutPanel2.ResumeLayout(false);
|
||||||
flowLayoutPanel_SourceFormat.ResumeLayout(false);
|
|
||||||
flowLayoutPanel_SourceFormat.PerformLayout();
|
|
||||||
ResumeLayout(false);
|
ResumeLayout(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,17 +281,13 @@
|
|||||||
private TableLayoutPanel tableLayoutPanel2;
|
private TableLayoutPanel tableLayoutPanel2;
|
||||||
private Button button_Ok;
|
private Button button_Ok;
|
||||||
private Button button_Cancel;
|
private Button button_Cancel;
|
||||||
private ListBox listBox_FilePath;
|
|
||||||
private Button button_SelectSkel;
|
|
||||||
private Label label_Tip;
|
|
||||||
private OpenFileDialog openFileDialog_Skel;
|
private OpenFileDialog openFileDialog_Skel;
|
||||||
private Label label1;
|
private Label label1;
|
||||||
private Label label2;
|
private Label label2;
|
||||||
private RadioButton radioButton_BinarySource;
|
|
||||||
private FlowLayoutPanel flowLayoutPanel_SourceFormat;
|
|
||||||
private RadioButton radioButton_JsonSource;
|
|
||||||
private FlowLayoutPanel flowLayoutPanel_TargetFormat;
|
private FlowLayoutPanel flowLayoutPanel_TargetFormat;
|
||||||
private RadioButton radioButton_BinaryTarget;
|
private RadioButton radioButton_BinaryTarget;
|
||||||
private RadioButton radioButton_JsonTarget;
|
private RadioButton radioButton_JsonTarget;
|
||||||
|
private Controls.SkelFileListBox skelFileListBox;
|
||||||
|
private ComboBox comboBox_TargetVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,62 +13,44 @@ namespace SpineViewer.Dialogs
|
|||||||
{
|
{
|
||||||
public partial class ConvertFileFormatDialog : Form
|
public partial class ConvertFileFormatDialog : Form
|
||||||
{
|
{
|
||||||
// TODO: 增加版本转换选项
|
/// <summary>
|
||||||
// TODO: 使用结果包装类
|
/// 对话框结果, 取消时为 null
|
||||||
public string[] SkelPaths { get; private set; }
|
/// </summary>
|
||||||
public Spine.Version SourceVersion { get; private set; }
|
public ConvertFileFormatDialogResult Result { get; private set; }
|
||||||
public Spine.Version TargetVersion { get; private set; }
|
|
||||||
public bool JsonSource { get; private set; }
|
|
||||||
public bool JsonTarget { get; private set; }
|
|
||||||
|
|
||||||
public ConvertFileFormatDialog()
|
public ConvertFileFormatDialog()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// XXX: 文件格式转换暂时不支持自动检测版本
|
comboBox_SourceVersion.DataSource = VersionHelper.Names.ToList();
|
||||||
var impVersions = VersionHelper.Names.ToDictionary();
|
|
||||||
impVersions.Remove(Spine.Version.Auto);
|
|
||||||
|
|
||||||
comboBox_SourceVersion.DataSource = impVersions.ToList();
|
|
||||||
comboBox_SourceVersion.DisplayMember = "Value";
|
comboBox_SourceVersion.DisplayMember = "Value";
|
||||||
comboBox_SourceVersion.ValueMember = "Key";
|
comboBox_SourceVersion.ValueMember = "Key";
|
||||||
comboBox_SourceVersion.SelectedValue = Spine.Version.V38;
|
comboBox_SourceVersion.SelectedValue = Spine.Version.Auto;
|
||||||
//comboBox_TargetVersion.DataSource = VersionHelper.Versions.ToList();
|
|
||||||
//comboBox_TargetVersion.DisplayMember = "Value";
|
|
||||||
//comboBox_TargetVersion.ValueMember = "Key";
|
|
||||||
//comboBox_TargetVersion.SelectedValue = Spine.Version.V38;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConvertFileFormatDialog_Load(object sender, EventArgs e)
|
// 目标版本不包含自动
|
||||||
{
|
var versionsWithoutAuto = VersionHelper.Names.ToDictionary();
|
||||||
button_SelectSkel_Click(sender, e);
|
versionsWithoutAuto.Remove(Spine.Version.Auto);
|
||||||
}
|
comboBox_TargetVersion.DataSource = versionsWithoutAuto.ToList();
|
||||||
|
comboBox_TargetVersion.DisplayMember = "Value";
|
||||||
private void button_SelectSkel_Click(object sender, EventArgs e)
|
comboBox_TargetVersion.ValueMember = "Key";
|
||||||
{
|
comboBox_TargetVersion.SelectedValue = Spine.Version.V38;
|
||||||
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)
|
private void button_Ok_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var sourceVersion = (Spine.Version)comboBox_SourceVersion.SelectedValue;
|
var sourceVersion = (Spine.Version)comboBox_SourceVersion.SelectedValue;
|
||||||
var targetVersion = (Spine.Version)comboBox_SourceVersion.SelectedValue; // TODO: 增加目标版本
|
var targetVersion = (Spine.Version)comboBox_TargetVersion.SelectedValue;
|
||||||
var jsonSource = radioButton_JsonSource.Checked;
|
|
||||||
var jsonTarget = radioButton_JsonTarget.Checked;
|
var jsonTarget = radioButton_JsonTarget.Checked;
|
||||||
|
|
||||||
if (listBox_FilePath.Items.Count <= 0)
|
var items = skelFileListBox.Items;
|
||||||
|
|
||||||
|
if (items.Count <= 0)
|
||||||
{
|
{
|
||||||
MessageBox.Info("未选择任何文件");
|
MessageBox.Info("未选择任何文件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string p in listBox_FilePath.Items)
|
foreach (string p in items)
|
||||||
{
|
{
|
||||||
if (!File.Exists(p))
|
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()} 版本尚未实现(咕咕咕~)");
|
MessageBox.Info($"{sourceVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
||||||
return;
|
return;
|
||||||
@@ -89,18 +71,7 @@ namespace SpineViewer.Dialogs
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonSource == jsonTarget && sourceVersion == targetVersion)
|
Result = new(items.Cast<string>().ToArray(), sourceVersion, targetVersion, jsonTarget);
|
||||||
{
|
|
||||||
MessageBox.Info($"不需要转换相同的格式和版本");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SkelPaths = listBox_FilePath.Items.Cast<string>().ToArray();
|
|
||||||
SourceVersion = sourceVersion;
|
|
||||||
TargetVersion = targetVersion;
|
|
||||||
JsonSource = jsonSource;
|
|
||||||
JsonTarget = jsonTarget;
|
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
DialogResult = DialogResult.OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,21 +79,31 @@ namespace SpineViewer.Dialogs
|
|||||||
{
|
{
|
||||||
DialogResult = DialogResult.Cancel;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void radioButton_Target_CheckedChanged(object sender, EventArgs e)
|
/// <summary>
|
||||||
|
/// 文件格式转换对话框结果包装类
|
||||||
|
/// </summary>
|
||||||
|
public class ConvertFileFormatDialogResult(string[] skelPaths, Spine.Version sourceVersion, Spine.Version targetVersion, bool jsonTarget)
|
||||||
{
|
{
|
||||||
if (radioButton_BinaryTarget.Checked)
|
/// <summary>
|
||||||
radioButton_JsonSource.Checked = true;
|
/// 骨骼文件路径列表
|
||||||
else
|
/// </summary>
|
||||||
radioButton_BinarySource.Checked = true;
|
public string[] SkelPaths => skelPaths;
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// 源版本
|
||||||
|
/// </summary>
|
||||||
|
public Spine.Version SourceVersion => sourceVersion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 目标版本
|
||||||
|
/// </summary>
|
||||||
|
public Spine.Version TargetVersion => targetVersion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 目标格式是否为 Json
|
||||||
|
/// </summary>
|
||||||
|
public bool JsonTarget => jsonTarget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
156
SpineViewer/Dialogs/ExportDialog.Designer.cs
generated
Normal file
156
SpineViewer/Dialogs/ExportDialog.Designer.cs
generated
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
namespace SpineViewer.Dialogs
|
||||||
|
{
|
||||||
|
partial class ExportDialog
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportDialog));
|
||||||
|
panel1 = new Panel();
|
||||||
|
tableLayoutPanel1 = new TableLayoutPanel();
|
||||||
|
propertyGrid_ExportArgs = new PropertyGrid();
|
||||||
|
tableLayoutPanel2 = new TableLayoutPanel();
|
||||||
|
button_Ok = new Button();
|
||||||
|
button_Cancel = new Button();
|
||||||
|
panel1.SuspendLayout();
|
||||||
|
tableLayoutPanel1.SuspendLayout();
|
||||||
|
tableLayoutPanel2.SuspendLayout();
|
||||||
|
SuspendLayout();
|
||||||
|
//
|
||||||
|
// panel1
|
||||||
|
//
|
||||||
|
panel1.Controls.Add(tableLayoutPanel1);
|
||||||
|
panel1.Dock = DockStyle.Fill;
|
||||||
|
panel1.Location = new Point(0, 0);
|
||||||
|
panel1.Name = "panel1";
|
||||||
|
panel1.Padding = new Padding(50, 15, 50, 10);
|
||||||
|
panel1.Size = new Size(710, 698);
|
||||||
|
panel1.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// tableLayoutPanel1
|
||||||
|
//
|
||||||
|
tableLayoutPanel1.AutoSize = true;
|
||||||
|
tableLayoutPanel1.ColumnCount = 1;
|
||||||
|
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.Controls.Add(propertyGrid_ExportArgs, 0, 0);
|
||||||
|
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
|
||||||
|
tableLayoutPanel1.Dock = DockStyle.Fill;
|
||||||
|
tableLayoutPanel1.Location = new Point(50, 15);
|
||||||
|
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||||
|
tableLayoutPanel1.RowCount = 2;
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle());
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
|
||||||
|
tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
|
||||||
|
tableLayoutPanel1.Size = new Size(610, 673);
|
||||||
|
tableLayoutPanel1.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// propertyGrid_ExportArgs
|
||||||
|
//
|
||||||
|
propertyGrid_ExportArgs.Dock = DockStyle.Fill;
|
||||||
|
propertyGrid_ExportArgs.Location = new Point(3, 3);
|
||||||
|
propertyGrid_ExportArgs.Name = "propertyGrid_ExportArgs";
|
||||||
|
propertyGrid_ExportArgs.PropertySort = PropertySort.Categorized;
|
||||||
|
propertyGrid_ExportArgs.Size = new Size(604, 594);
|
||||||
|
propertyGrid_ExportArgs.TabIndex = 1;
|
||||||
|
propertyGrid_ExportArgs.ToolbarVisible = false;
|
||||||
|
//
|
||||||
|
// tableLayoutPanel2
|
||||||
|
//
|
||||||
|
tableLayoutPanel2.AutoSize = true;
|
||||||
|
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
|
tableLayoutPanel2.ColumnCount = 2;
|
||||||
|
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
||||||
|
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, 630);
|
||||||
|
tableLayoutPanel2.Margin = new Padding(3, 30, 3, 3);
|
||||||
|
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||||
|
tableLayoutPanel2.RowCount = 1;
|
||||||
|
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
||||||
|
tableLayoutPanel2.Size = new Size(604, 40);
|
||||||
|
tableLayoutPanel2.TabIndex = 10;
|
||||||
|
//
|
||||||
|
// button_Ok
|
||||||
|
//
|
||||||
|
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
||||||
|
button_Ok.Location = new Point(160, 3);
|
||||||
|
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
||||||
|
button_Ok.Name = "button_Ok";
|
||||||
|
button_Ok.Size = new Size(112, 34);
|
||||||
|
button_Ok.TabIndex = 7;
|
||||||
|
button_Ok.Text = "确认";
|
||||||
|
button_Ok.UseVisualStyleBackColor = true;
|
||||||
|
button_Ok.Click += button_Ok_Click;
|
||||||
|
//
|
||||||
|
// button_Cancel
|
||||||
|
//
|
||||||
|
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
||||||
|
button_Cancel.Location = new Point(332, 3);
|
||||||
|
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
||||||
|
button_Cancel.Name = "button_Cancel";
|
||||||
|
button_Cancel.Size = new Size(112, 34);
|
||||||
|
button_Cancel.TabIndex = 8;
|
||||||
|
button_Cancel.Text = "取消";
|
||||||
|
button_Cancel.UseVisualStyleBackColor = true;
|
||||||
|
button_Cancel.Click += button_Cancel_Click;
|
||||||
|
//
|
||||||
|
// ExportDialog
|
||||||
|
//
|
||||||
|
AcceptButton = button_Ok;
|
||||||
|
AutoScaleDimensions = new SizeF(11F, 24F);
|
||||||
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
|
CancelButton = button_Cancel;
|
||||||
|
ClientSize = new Size(710, 698);
|
||||||
|
Controls.Add(panel1);
|
||||||
|
FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
Icon = (Icon)resources.GetObject("$this.Icon");
|
||||||
|
MaximizeBox = false;
|
||||||
|
MinimizeBox = false;
|
||||||
|
Name = "ExportDialog";
|
||||||
|
ShowInTaskbar = false;
|
||||||
|
StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
Text = "导出参数";
|
||||||
|
panel1.ResumeLayout(false);
|
||||||
|
panel1.PerformLayout();
|
||||||
|
tableLayoutPanel1.ResumeLayout(false);
|
||||||
|
tableLayoutPanel1.PerformLayout();
|
||||||
|
tableLayoutPanel2.ResumeLayout(false);
|
||||||
|
ResumeLayout(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Panel panel1;
|
||||||
|
private TableLayoutPanel tableLayoutPanel1;
|
||||||
|
private TableLayoutPanel tableLayoutPanel2;
|
||||||
|
private Button button_Ok;
|
||||||
|
private Button button_Cancel;
|
||||||
|
private PropertyGrid propertyGrid_ExportArgs;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
SpineViewer/Dialogs/ExportDialog.cs
Normal file
92
SpineViewer/Dialogs/ExportDialog.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using SpineViewer.Exporter;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace SpineViewer.Dialogs
|
||||||
|
{
|
||||||
|
public partial class ExportDialog: Form
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 要绑定的导出参数
|
||||||
|
/// </summary>
|
||||||
|
public required ExportArgs ExportArgs
|
||||||
|
{
|
||||||
|
get => propertyGrid_ExportArgs.SelectedObject as ExportArgs;
|
||||||
|
init
|
||||||
|
{
|
||||||
|
propertyGrid_ExportArgs.SelectedObject = value;
|
||||||
|
|
||||||
|
#region XXX: 通过反射默认高亮指定的项
|
||||||
|
var categories = propertyGrid_ExportArgs.SelectedGridItem?.Parent?.Parent?.GridItems;
|
||||||
|
if (categories is null) return;
|
||||||
|
|
||||||
|
foreach (var category in categories)
|
||||||
|
{
|
||||||
|
// 查找 "导出" 分组
|
||||||
|
if (category == null) continue;
|
||||||
|
PropertyInfo? labelProp = category.GetType().GetProperty("Label", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
if (labelProp == null) continue;
|
||||||
|
string? label = labelProp.GetValue(category) as string;
|
||||||
|
if (label != "导出") continue;
|
||||||
|
|
||||||
|
// 获取该分组下的所有属性项
|
||||||
|
PropertyInfo? gridItemsProp = category.GetType().GetProperty("GridItems", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
if (gridItemsProp == null) continue;
|
||||||
|
var gridItemsObj = gridItemsProp.GetValue(category);
|
||||||
|
if (gridItemsObj is not IEnumerable gridItems) continue;
|
||||||
|
|
||||||
|
foreach (object item in gridItems)
|
||||||
|
{
|
||||||
|
if (item == null) continue;
|
||||||
|
PropertyInfo? propDescProp = item.GetType().GetProperty("PropertyDescriptor", BindingFlags.Instance | BindingFlags.Public);
|
||||||
|
if (propDescProp == null) continue;
|
||||||
|
var propDesc = propDescProp.GetValue(item) as PropertyDescriptor;
|
||||||
|
if (propDesc == null) continue;
|
||||||
|
if (propDesc.Name == "OutputDir")
|
||||||
|
{
|
||||||
|
|
||||||
|
if (item is GridItem gridItem)
|
||||||
|
propertyGrid_ExportArgs.SelectedGridItem = gridItem; // 找到后,将此项设为选中项
|
||||||
|
else
|
||||||
|
propertyGrid_ExportArgs.SelectedGridItem = (GridItem)item; // 如果转换失败,则尝试直接赋值
|
||||||
|
}
|
||||||
|
return; // 设置成功后退出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_Ok_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (ExportArgs.Validate() is string error)
|
||||||
|
{
|
||||||
|
MessageBox.Info(error, "参数错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void button_Cancel_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<metadata name="folderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
<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">
|
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
<value>
|
<value>
|
||||||
270
SpineViewer/Dialogs/ExportPngDialog.Designer.cs
generated
270
SpineViewer/Dialogs/ExportPngDialog.Designer.cs
generated
@@ -1,270 +0,0 @@
|
|||||||
namespace SpineViewer.Dialogs
|
|
||||||
{
|
|
||||||
partial class ExportPngDialog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportPngDialog));
|
|
||||||
panel1 = new Panel();
|
|
||||||
tableLayoutPanel1 = new TableLayoutPanel();
|
|
||||||
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_Duration = new NumericUpDown();
|
|
||||||
numericUpDown_Fps = new NumericUpDown();
|
|
||||||
folderBrowserDialog = new FolderBrowserDialog();
|
|
||||||
panel1.SuspendLayout();
|
|
||||||
tableLayoutPanel1.SuspendLayout();
|
|
||||||
tableLayoutPanel2.SuspendLayout();
|
|
||||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Duration).BeginInit();
|
|
||||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Fps).BeginInit();
|
|
||||||
SuspendLayout();
|
|
||||||
//
|
|
||||||
// panel1
|
|
||||||
//
|
|
||||||
panel1.Controls.Add(tableLayoutPanel1);
|
|
||||||
panel1.Dock = DockStyle.Fill;
|
|
||||||
panel1.Location = new Point(0, 0);
|
|
||||||
panel1.Name = "panel1";
|
|
||||||
panel1.Padding = new Padding(50, 15, 50, 10);
|
|
||||||
panel1.Size = new Size(919, 276);
|
|
||||||
panel1.TabIndex = 1;
|
|
||||||
//
|
|
||||||
// tableLayoutPanel1
|
|
||||||
//
|
|
||||||
tableLayoutPanel1.AutoSize = true;
|
|
||||||
tableLayoutPanel1.ColumnCount = 4;
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
|
||||||
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_Duration, 1, 2);
|
|
||||||
tableLayoutPanel1.Controls.Add(numericUpDown_Fps, 1, 3);
|
|
||||||
tableLayoutPanel1.Dock = DockStyle.Fill;
|
|
||||||
tableLayoutPanel1.Location = new Point(50, 15);
|
|
||||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
|
||||||
tableLayoutPanel1.RowCount = 5;
|
|
||||||
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(819, 251);
|
|
||||||
tableLayoutPanel1.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// label4
|
|
||||||
//
|
|
||||||
label4.AutoSize = true;
|
|
||||||
tableLayoutPanel1.SetColumnSpan(label4, 4);
|
|
||||||
label4.Dock = DockStyle.Fill;
|
|
||||||
label4.Location = new Point(15, 15);
|
|
||||||
label4.Margin = new Padding(15);
|
|
||||||
label4.Name = "label4";
|
|
||||||
label4.Size = new Size(789, 24);
|
|
||||||
label4.TabIndex = 11;
|
|
||||||
label4.Text = "说明:时长不足一帧时仅导出第一帧";
|
|
||||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
label1.Anchor = AnchorStyles.Right;
|
|
||||||
label1.AutoSize = true;
|
|
||||||
label1.Location = new Point(3, 62);
|
|
||||||
label1.Name = "label1";
|
|
||||||
label1.Size = new Size(104, 24);
|
|
||||||
label1.TabIndex = 0;
|
|
||||||
label1.Text = "输出文件夹:";
|
|
||||||
//
|
|
||||||
// label2
|
|
||||||
//
|
|
||||||
label2.Anchor = AnchorStyles.Right;
|
|
||||||
label2.AutoSize = true;
|
|
||||||
label2.Location = new Point(57, 100);
|
|
||||||
label2.Name = "label2";
|
|
||||||
label2.Size = new Size(50, 24);
|
|
||||||
label2.TabIndex = 1;
|
|
||||||
label2.Text = "时长:";
|
|
||||||
//
|
|
||||||
// label3
|
|
||||||
//
|
|
||||||
label3.Anchor = AnchorStyles.Right;
|
|
||||||
label3.AutoSize = true;
|
|
||||||
label3.Location = new Point(57, 136);
|
|
||||||
label3.Name = "label3";
|
|
||||||
label3.Size = new Size(50, 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.TabIndex = 3;
|
|
||||||
//
|
|
||||||
// button_SelectOutputDir
|
|
||||||
//
|
|
||||||
button_SelectOutputDir.AutoSize = true;
|
|
||||||
button_SelectOutputDir.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
|
||||||
button_SelectOutputDir.Location = new Point(783, 57);
|
|
||||||
button_SelectOutputDir.Name = "button_SelectOutputDir";
|
|
||||||
button_SelectOutputDir.Size = new Size(32, 34);
|
|
||||||
button_SelectOutputDir.TabIndex = 5;
|
|
||||||
button_SelectOutputDir.Text = "...";
|
|
||||||
button_SelectOutputDir.UseVisualStyleBackColor = true;
|
|
||||||
button_SelectOutputDir.Click += button_SelectOutputDir_Click;
|
|
||||||
//
|
|
||||||
// tableLayoutPanel2
|
|
||||||
//
|
|
||||||
tableLayoutPanel2.AutoSize = true;
|
|
||||||
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
|
||||||
tableLayoutPanel2.ColumnCount = 2;
|
|
||||||
tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4);
|
|
||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
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, 208);
|
|
||||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
|
||||||
tableLayoutPanel2.RowCount = 1;
|
|
||||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel2.Size = new Size(813, 40);
|
|
||||||
tableLayoutPanel2.TabIndex = 10;
|
|
||||||
//
|
|
||||||
// button_Ok
|
|
||||||
//
|
|
||||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
|
||||||
button_Ok.Location = new Point(264, 3);
|
|
||||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
|
||||||
button_Ok.Name = "button_Ok";
|
|
||||||
button_Ok.Size = new Size(112, 34);
|
|
||||||
button_Ok.TabIndex = 7;
|
|
||||||
button_Ok.Text = "确认";
|
|
||||||
button_Ok.UseVisualStyleBackColor = true;
|
|
||||||
button_Ok.Click += button_Ok_Click;
|
|
||||||
//
|
|
||||||
// button_Cancel
|
|
||||||
//
|
|
||||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
|
||||||
button_Cancel.Location = new Point(436, 3);
|
|
||||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
|
||||||
button_Cancel.Name = "button_Cancel";
|
|
||||||
button_Cancel.Size = new Size(112, 34);
|
|
||||||
button_Cancel.TabIndex = 8;
|
|
||||||
button_Cancel.Text = "取消";
|
|
||||||
button_Cancel.UseVisualStyleBackColor = true;
|
|
||||||
button_Cancel.Click += button_Cancel_Click;
|
|
||||||
//
|
|
||||||
// numericUpDown_Duration
|
|
||||||
//
|
|
||||||
numericUpDown_Duration.Anchor = AnchorStyles.Left;
|
|
||||||
numericUpDown_Duration.DecimalPlaces = 3;
|
|
||||||
numericUpDown_Duration.Location = new Point(113, 97);
|
|
||||||
numericUpDown_Duration.Maximum = new decimal(new int[] { 300, 0, 0, 0 });
|
|
||||||
numericUpDown_Duration.Name = "numericUpDown_Duration";
|
|
||||||
numericUpDown_Duration.Size = new Size(180, 30);
|
|
||||||
numericUpDown_Duration.TabIndex = 12;
|
|
||||||
numericUpDown_Duration.TextAlign = HorizontalAlignment.Right;
|
|
||||||
numericUpDown_Duration.Value = new decimal(new int[] { 1, 0, 0, 0 });
|
|
||||||
//
|
|
||||||
// numericUpDown_Fps
|
|
||||||
//
|
|
||||||
numericUpDown_Fps.Anchor = AnchorStyles.Left;
|
|
||||||
numericUpDown_Fps.Location = new Point(113, 133);
|
|
||||||
numericUpDown_Fps.Maximum = new decimal(new int[] { 300, 0, 0, 0 });
|
|
||||||
numericUpDown_Fps.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
|
|
||||||
numericUpDown_Fps.Name = "numericUpDown_Fps";
|
|
||||||
numericUpDown_Fps.Size = new Size(180, 30);
|
|
||||||
numericUpDown_Fps.TabIndex = 13;
|
|
||||||
numericUpDown_Fps.TextAlign = HorizontalAlignment.Right;
|
|
||||||
numericUpDown_Fps.Value = new decimal(new int[] { 60, 0, 0, 0 });
|
|
||||||
//
|
|
||||||
// folderBrowserDialog
|
|
||||||
//
|
|
||||||
folderBrowserDialog.AddToRecent = false;
|
|
||||||
//
|
|
||||||
// ExportPngDialog
|
|
||||||
//
|
|
||||||
AcceptButton = button_Ok;
|
|
||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
|
||||||
CancelButton = button_Cancel;
|
|
||||||
ClientSize = new Size(919, 276);
|
|
||||||
Controls.Add(panel1);
|
|
||||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
||||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
|
||||||
MaximizeBox = false;
|
|
||||||
MinimizeBox = false;
|
|
||||||
Name = "ExportPngDialog";
|
|
||||||
ShowInTaskbar = false;
|
|
||||||
StartPosition = FormStartPosition.CenterScreen;
|
|
||||||
Text = "导出PNG序列";
|
|
||||||
Load += ExportPngDialog_Load;
|
|
||||||
panel1.ResumeLayout(false);
|
|
||||||
panel1.PerformLayout();
|
|
||||||
tableLayoutPanel1.ResumeLayout(false);
|
|
||||||
tableLayoutPanel1.PerformLayout();
|
|
||||||
tableLayoutPanel2.ResumeLayout(false);
|
|
||||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Duration).EndInit();
|
|
||||||
((System.ComponentModel.ISupportInitialize)numericUpDown_Fps).EndInit();
|
|
||||||
ResumeLayout(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private Panel panel1;
|
|
||||||
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_Duration;
|
|
||||||
private NumericUpDown numericUpDown_Fps;
|
|
||||||
private FolderBrowserDialog folderBrowserDialog;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace SpineViewer.Dialogs
|
|
||||||
{
|
|
||||||
public partial class ExportPngDialog : Form
|
|
||||||
{
|
|
||||||
// TODO: 该对话框要合并到统一的导出参数对话框
|
|
||||||
// TODO: 使用结果包装类
|
|
||||||
public string OutputDir { get; private set; }
|
|
||||||
public float Duration { get; private set; }
|
|
||||||
public uint Fps { get; private set; }
|
|
||||||
|
|
||||||
public ExportPngDialog()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExportPngDialog_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
button_SelectOutputDir_Click(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Ok_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var outputDir = textBox_OutputDir.Text;
|
|
||||||
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);
|
|
||||||
Duration = (float)numericUpDown_Duration.Value;
|
|
||||||
Fps = (uint)numericUpDown_Fps.Value;
|
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Cancel_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
270
SpineViewer/Dialogs/ExportPreviewDialog.Designer.cs
generated
270
SpineViewer/Dialogs/ExportPreviewDialog.Designer.cs
generated
@@ -1,270 +0,0 @@
|
|||||||
namespace SpineViewer.Dialogs
|
|
||||||
{
|
|
||||||
partial class ExportPreviewDialog
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExportPreviewDialog));
|
|
||||||
panel1 = new Panel();
|
|
||||||
tableLayoutPanel1 = new TableLayoutPanel();
|
|
||||||
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
|
|
||||||
//
|
|
||||||
panel1.Controls.Add(tableLayoutPanel1);
|
|
||||||
panel1.Dock = DockStyle.Fill;
|
|
||||||
panel1.Location = new Point(0, 0);
|
|
||||||
panel1.Name = "panel1";
|
|
||||||
panel1.Padding = new Padding(50, 15, 50, 10);
|
|
||||||
panel1.Size = new Size(919, 276);
|
|
||||||
panel1.TabIndex = 2;
|
|
||||||
//
|
|
||||||
// tableLayoutPanel1
|
|
||||||
//
|
|
||||||
tableLayoutPanel1.AutoSize = true;
|
|
||||||
tableLayoutPanel1.ColumnCount = 4;
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle());
|
|
||||||
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.Dock = DockStyle.Fill;
|
|
||||||
tableLayoutPanel1.Location = new Point(50, 15);
|
|
||||||
tableLayoutPanel1.Name = "tableLayoutPanel1";
|
|
||||||
tableLayoutPanel1.RowCount = 5;
|
|
||||||
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(819, 251);
|
|
||||||
tableLayoutPanel1.TabIndex = 0;
|
|
||||||
//
|
|
||||||
// label4
|
|
||||||
//
|
|
||||||
label4.AutoSize = true;
|
|
||||||
tableLayoutPanel1.SetColumnSpan(label4, 4);
|
|
||||||
label4.Dock = DockStyle.Fill;
|
|
||||||
label4.Location = new Point(15, 15);
|
|
||||||
label4.Margin = new Padding(15);
|
|
||||||
label4.Name = "label4";
|
|
||||||
label4.Size = new Size(789, 24);
|
|
||||||
label4.TabIndex = 11;
|
|
||||||
label4.Text = "说明:导出的文件名与骨骼文件名相同";
|
|
||||||
label4.TextAlign = ContentAlignment.MiddleCenter;
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
label1.Anchor = AnchorStyles.Right;
|
|
||||||
label1.AutoSize = true;
|
|
||||||
label1.Location = new Point(3, 62);
|
|
||||||
label1.Name = "label1";
|
|
||||||
label1.Size = new Size(104, 24);
|
|
||||||
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.TabIndex = 3;
|
|
||||||
//
|
|
||||||
// button_SelectOutputDir
|
|
||||||
//
|
|
||||||
button_SelectOutputDir.AutoSize = true;
|
|
||||||
button_SelectOutputDir.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
|
||||||
button_SelectOutputDir.Location = new Point(783, 57);
|
|
||||||
button_SelectOutputDir.Name = "button_SelectOutputDir";
|
|
||||||
button_SelectOutputDir.Size = new Size(32, 34);
|
|
||||||
button_SelectOutputDir.TabIndex = 5;
|
|
||||||
button_SelectOutputDir.Text = "...";
|
|
||||||
button_SelectOutputDir.UseVisualStyleBackColor = true;
|
|
||||||
button_SelectOutputDir.Click += button_SelectOutputDir_Click;
|
|
||||||
//
|
|
||||||
// tableLayoutPanel2
|
|
||||||
//
|
|
||||||
tableLayoutPanel2.AutoSize = true;
|
|
||||||
tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
|
||||||
tableLayoutPanel2.ColumnCount = 2;
|
|
||||||
tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4);
|
|
||||||
tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
|
|
||||||
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, 208);
|
|
||||||
tableLayoutPanel2.Name = "tableLayoutPanel2";
|
|
||||||
tableLayoutPanel2.RowCount = 1;
|
|
||||||
tableLayoutPanel2.RowStyles.Add(new RowStyle());
|
|
||||||
tableLayoutPanel2.Size = new Size(813, 40);
|
|
||||||
tableLayoutPanel2.TabIndex = 10;
|
|
||||||
//
|
|
||||||
// button_Ok
|
|
||||||
//
|
|
||||||
button_Ok.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
|
|
||||||
button_Ok.Location = new Point(264, 3);
|
|
||||||
button_Ok.Margin = new Padding(3, 3, 30, 3);
|
|
||||||
button_Ok.Name = "button_Ok";
|
|
||||||
button_Ok.Size = new Size(112, 34);
|
|
||||||
button_Ok.TabIndex = 7;
|
|
||||||
button_Ok.Text = "确认";
|
|
||||||
button_Ok.UseVisualStyleBackColor = true;
|
|
||||||
button_Ok.Click += button_Ok_Click;
|
|
||||||
//
|
|
||||||
// button_Cancel
|
|
||||||
//
|
|
||||||
button_Cancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
|
|
||||||
button_Cancel.Location = new Point(436, 3);
|
|
||||||
button_Cancel.Margin = new Padding(30, 3, 3, 3);
|
|
||||||
button_Cancel.Name = "button_Cancel";
|
|
||||||
button_Cancel.Size = new Size(112, 34);
|
|
||||||
button_Cancel.TabIndex = 8;
|
|
||||||
button_Cancel.Text = "取消";
|
|
||||||
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;
|
|
||||||
//
|
|
||||||
// ExportPreviewDialog
|
|
||||||
//
|
|
||||||
AcceptButton = button_Ok;
|
|
||||||
AutoScaleDimensions = new SizeF(11F, 24F);
|
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
|
||||||
CancelButton = button_Cancel;
|
|
||||||
ClientSize = new Size(919, 276);
|
|
||||||
Controls.Add(panel1);
|
|
||||||
FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
||||||
Icon = (Icon)resources.GetObject("$this.Icon");
|
|
||||||
MaximizeBox = false;
|
|
||||||
MinimizeBox = false;
|
|
||||||
Name = "ExportPreviewDialog";
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private Panel panel1;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
||||||
public ExportPreviewDialog()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExportPreviewDialog_Load(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
button_SelectOutputDir_Click(sender, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Ok_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var outputDir = textBox_OutputDir.Text;
|
|
||||||
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);
|
|
||||||
PreviewWidth = (uint)numericUpDown_Width.Value;
|
|
||||||
PreviewHeight = (uint)numericUpDown_Height.Value;
|
|
||||||
|
|
||||||
DialogResult = DialogResult.OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void button_Cancel_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
DialogResult = DialogResult.Cancel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
107
SpineViewer/Exporter/ExportArgs.cs
Normal file
107
SpineViewer/Exporter/ExportArgs.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using SpineViewer.Spine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 导出参数基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 实现类缓存
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<ExportType, Type> ImplementationTypes = [];
|
||||||
|
|
||||||
|
static ExportArgs()
|
||||||
|
{
|
||||||
|
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ExportArgs).IsAssignableFrom(t) && !t.IsAbstract);
|
||||||
|
foreach (var type in impTypes)
|
||||||
|
{
|
||||||
|
var attr = type.GetCustomAttribute<ExportImplementationAttribute>();
|
||||||
|
if (attr is not null)
|
||||||
|
{
|
||||||
|
if (ImplementationTypes.ContainsKey(attr.ExportType))
|
||||||
|
throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
|
||||||
|
ImplementationTypes[attr.ExportType] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Program.Logger.Debug("Find export args implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建指定类型导出参数
|
||||||
|
/// </summary>
|
||||||
|
public static ExportArgs New(ExportType exportType, Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
||||||
|
{
|
||||||
|
if (!ImplementationTypes.TryGetValue(exportType, out var type))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Not implemented type: {exportType}");
|
||||||
|
}
|
||||||
|
return (ExportArgs)Activator.CreateInstance(type, resolution, view, renderSelectedOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
||||||
|
{
|
||||||
|
Resolution = resolution;
|
||||||
|
View = view;
|
||||||
|
RenderSelectedOnly = renderSelectedOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输出文件夹
|
||||||
|
/// </summary>
|
||||||
|
[Editor(typeof(FolderNameEditor), typeof(UITypeEditor))]
|
||||||
|
[Category("导出"), DisplayName("输出文件夹"), Description("逐个导出时可以留空,将逐个导出到模型自身所在目录")]
|
||||||
|
public string? OutputDir { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出单个
|
||||||
|
/// </summary>
|
||||||
|
[Category("导出"), DisplayName("导出单个"), Description("是否将模型在同一个画面上导出单个文件,否则逐个导出模型")]
|
||||||
|
public bool ExportSingle { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 画面分辨率
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(SizeConverter))]
|
||||||
|
[Category("导出"), DisplayName("分辨率"), Description("画面的宽高像素大小,请在预览画面参数面板进行调整")]
|
||||||
|
public Size Resolution { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 渲染视窗
|
||||||
|
/// </summary>
|
||||||
|
[Category("导出"), DisplayName("视图"), Description("画面的视图参数,请在预览画面参数面板进行调整")]
|
||||||
|
public SFML.Graphics.View View { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否仅渲染选中
|
||||||
|
/// </summary>
|
||||||
|
[Category("导出"), DisplayName("仅渲染选中"), Description("是否仅导出选中的模型,请在预览画面参数面板进行调整")]
|
||||||
|
public bool RenderSelectedOnly { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查参数是否合法并规范化参数值, 否则返回用户错误原因
|
||||||
|
/// </summary>
|
||||||
|
public virtual string? Validate()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(OutputDir) && File.Exists(OutputDir))
|
||||||
|
return "输出文件夹无效";
|
||||||
|
if (!string.IsNullOrEmpty(OutputDir) && !Directory.Exists(OutputDir))
|
||||||
|
return $"文件夹 {OutputDir} 不存在";
|
||||||
|
if (ExportSingle && string.IsNullOrEmpty(OutputDir))
|
||||||
|
return "导出单个时必须提供输出文件夹";
|
||||||
|
|
||||||
|
OutputDir = string.IsNullOrEmpty(OutputDir) ? null : Path.GetFullPath(OutputDir);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
140
SpineViewer/Exporter/ExportHelper.cs
Normal file
140
SpineViewer/Exporter/ExportHelper.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using FFMpegCore.Pipes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 导出类型
|
||||||
|
/// </summary>
|
||||||
|
public enum ExportType
|
||||||
|
{
|
||||||
|
Frame,
|
||||||
|
FrameSequence,
|
||||||
|
GIF,
|
||||||
|
MKV,
|
||||||
|
MP4,
|
||||||
|
MOV,
|
||||||
|
WebM
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出实现类标记
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class ExportImplementationAttribute : Attribute
|
||||||
|
{
|
||||||
|
public ExportType ExportType { get; }
|
||||||
|
|
||||||
|
public ExportImplementationAttribute(ExportType exportType)
|
||||||
|
{
|
||||||
|
ExportType = exportType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// 获取 Winforms Bitmap 对象
|
||||||
|
/// </summary>
|
||||||
|
public Bitmap CopyToBitmap()
|
||||||
|
{
|
||||||
|
image.SaveToMemory(out var imgBuffer, "bmp");
|
||||||
|
using var stream = new MemoryStream(imgBuffer);
|
||||||
|
return new(new Bitmap(stream)); // 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为帧导出创建的辅助类
|
||||||
|
/// </summary>
|
||||||
|
public static class ExportHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 根据 Bitmap 文件格式获取合适的文件后缀
|
||||||
|
/// </summary>
|
||||||
|
public static string GetSuffix(this ImageFormat imageFormat)
|
||||||
|
{
|
||||||
|
if (imageFormat == ImageFormat.Icon) return ".ico";
|
||||||
|
else if (imageFormat == ImageFormat.Exif) return ".jpeg";
|
||||||
|
else return $".{imageFormat.ToString().ToLower()}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 包围盒辅助函数
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, Size resolution, Padding padding)
|
||||||
|
=> bounds.GetView((uint)resolution.Width, (uint)resolution.Height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, uint width, uint height, Padding padding)
|
||||||
|
=> bounds.GetView(width, height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, Size resolution, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
||||||
|
=> bounds.GetView((uint)resolution.Width, (uint)resolution.Height, paddingL, paddingR, paddingT, paddingB);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取某个包围盒下合适的视图
|
||||||
|
/// </summary>
|
||||||
|
public static SFML.Graphics.View GetView(this RectangleF bounds, uint width, uint height, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
||||||
|
{
|
||||||
|
float sizeX = bounds.Width;
|
||||||
|
float sizeY = bounds.Height;
|
||||||
|
float innerW = width - paddingL - paddingR;
|
||||||
|
float innerH = height - paddingT - paddingB;
|
||||||
|
|
||||||
|
float scale = 1;
|
||||||
|
if (sizeY / sizeX < innerH / innerW)
|
||||||
|
scale = sizeX / innerW; // 相同的 X, 视窗 Y 更大
|
||||||
|
else
|
||||||
|
scale = sizeY / innerH; // 相同的 Y, 视窗 X 更大
|
||||||
|
|
||||||
|
var x = bounds.X + bounds.Width / 2 + (paddingL - (float)paddingR) * scale;
|
||||||
|
var y = bounds.Y + bounds.Height / 2 + (paddingT - (float)paddingB) * scale;
|
||||||
|
var viewX = width * scale;
|
||||||
|
var viewY = height * scale;
|
||||||
|
|
||||||
|
return new(new(x, y), new(viewX, -viewY));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
126
SpineViewer/Exporter/Exporter.cs
Normal file
126
SpineViewer/Exporter/Exporter.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using SpineViewer.Spine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 导出器基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 实现类缓存
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<ExportType, Type> ImplementationTypes = [];
|
||||||
|
|
||||||
|
static Exporter()
|
||||||
|
{
|
||||||
|
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Exporter).IsAssignableFrom(t) && !t.IsAbstract);
|
||||||
|
foreach (var type in impTypes)
|
||||||
|
{
|
||||||
|
var attr = type.GetCustomAttribute<ExportImplementationAttribute>();
|
||||||
|
if (attr is not null)
|
||||||
|
{
|
||||||
|
if (ImplementationTypes.ContainsKey(attr.ExportType))
|
||||||
|
throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
|
||||||
|
ImplementationTypes[attr.ExportType] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Program.Logger.Debug("Find exporter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建指定类型导出参数
|
||||||
|
/// </summary>
|
||||||
|
public static Exporter New(ExportType exportType, ExportArgs exportArgs)
|
||||||
|
{
|
||||||
|
if (!ImplementationTypes.TryGetValue(exportType, out var type))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException($"Not implemented type: {exportType}");
|
||||||
|
}
|
||||||
|
return (Exporter)Activator.CreateInstance(type, exportArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出参数
|
||||||
|
/// </summary>
|
||||||
|
public ExportArgs ExportArgs { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 渲染目标
|
||||||
|
/// </summary>
|
||||||
|
private SFML.Graphics.RenderTexture tex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 可用于文件名的时间戳字符串
|
||||||
|
/// </summary>
|
||||||
|
protected readonly string timestamp;
|
||||||
|
|
||||||
|
public Exporter(ExportArgs exportArgs)
|
||||||
|
{
|
||||||
|
ExportArgs = exportArgs;
|
||||||
|
timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取单个模型的单帧画面
|
||||||
|
/// </summary>
|
||||||
|
protected SFMLImageVideoFrame GetFrame(Spine.Spine spine)
|
||||||
|
{
|
||||||
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
|
tex.Draw(spine);
|
||||||
|
tex.Display();
|
||||||
|
return new(tex.Texture.CopyToImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取模型列表的单帧画面
|
||||||
|
/// </summary>
|
||||||
|
protected SFMLImageVideoFrame GetFrame(Spine.Spine[] spinesToRender)
|
||||||
|
{
|
||||||
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
|
foreach (var spine in spinesToRender) tex.Draw(spine);
|
||||||
|
tex.Display();
|
||||||
|
return new(tex.Texture.CopyToImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每个模型在同一个画面进行导出
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void ExportSingle(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 每个模型独立导出
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void ExportIndividual(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行导出
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="spines">要进行导出的 Spine 列表</param>
|
||||||
|
/// <param name="worker">用来执行该函数的 worker</param>
|
||||||
|
public virtual void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var spinesToRender = spines.Where(sp => !ExportArgs.RenderSelectedOnly || sp.IsSelected).Reverse().ToArray();
|
||||||
|
|
||||||
|
// tex 必须临时创建, 防止出现跨线程的情况
|
||||||
|
using (tex = new SFML.Graphics.RenderTexture((uint)ExportArgs.Resolution.Width, (uint)ExportArgs.Resolution.Height))
|
||||||
|
{
|
||||||
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
|
tex.SetView(ExportArgs.View);
|
||||||
|
if (ExportArgs.ExportSingle) ExportSingle(spinesToRender, worker);
|
||||||
|
else ExportIndividual(spinesToRender, worker);
|
||||||
|
}
|
||||||
|
tex = null;
|
||||||
|
|
||||||
|
Program.LogCurrentMemoryUsage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 单帧画面导出参数
|
||||||
|
/// </summary>
|
||||||
|
[ExportImplementation(ExportType.Frame)]
|
||||||
|
public class FrameExportArgs : SpineViewer.Exporter.ExportArgs
|
||||||
|
{
|
||||||
|
public FrameExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly) : base(resolution, view, renderSelectedOnly) { }
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
[Category("单帧画面"), DisplayName("文件名后缀"), Description("与图像格式匹配的文件名后缀")]
|
||||||
|
public string FileSuffix { get => imageFormat.GetSuffix(); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DPI
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(SizeFConverter))]
|
||||||
|
[Category("单帧画面"), DisplayName("DPI"), Description("导出图像的每英寸像素数,用于调整图像的物理尺寸")]
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 帧序列导出参数
|
||||||
|
/// </summary>
|
||||||
|
[ExportImplementation(ExportType.FrameSequence)]
|
||||||
|
public class FrameSequenceExportArgs : VideoExportArgs
|
||||||
|
{
|
||||||
|
public FrameSequenceExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly) : base(resolution, view, renderSelectedOnly) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件名后缀
|
||||||
|
/// </summary>
|
||||||
|
[TypeConverter(typeof(SFMLImageFileSuffixConverter))]
|
||||||
|
[Category("帧序列参数"), DisplayName("文件名后缀"), Description("帧文件的后缀,同时决定帧图像格式")]
|
||||||
|
public string FileSuffix { get; set; } = ".png";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.ExportArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 视频导出参数基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class VideoExportArgs : SpineViewer.Exporter.ExportArgs
|
||||||
|
{
|
||||||
|
public VideoExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly) : base(resolution, view, renderSelectedOnly) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 导出时长
|
||||||
|
/// </summary>
|
||||||
|
[Category("视频参数"), DisplayName("时长"), Description("可以从模型列表查看动画时长")]
|
||||||
|
public float Duration { get => duration; set => duration = Math.Max(0, value); }
|
||||||
|
private float duration = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 帧率
|
||||||
|
/// </summary>
|
||||||
|
[Category("视频参数"), DisplayName("帧率"), Description("每秒画面数")]
|
||||||
|
public float FPS { get; set; } = 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
using SpineViewer.Exporter.Implementations.ExportArgs;
|
||||||
|
using SpineViewer.Spine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 单帧画面导出器
|
||||||
|
/// </summary>
|
||||||
|
[ExportImplementation(ExportType.Frame)]
|
||||||
|
public class FrameExporter : SpineViewer.Exporter.Exporter
|
||||||
|
{
|
||||||
|
public FrameExporter(FrameExportArgs exportArgs) : base(exportArgs) { }
|
||||||
|
|
||||||
|
protected override void ExportSingle(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (FrameExportArgs)ExportArgs;
|
||||||
|
|
||||||
|
// 导出单个时必定提供输出文件夹
|
||||||
|
var filename = $"frame_{timestamp}{args.FileSuffix}";
|
||||||
|
var savePath = Path.Combine(args.OutputDir, filename);
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"已处理 0/1");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var frame = GetFrame(spinesToRender);
|
||||||
|
using var img = frame.CopyToBitmap();
|
||||||
|
img.SetResolution(args.DPI.Width, args.DPI.Height);
|
||||||
|
img.Save(savePath, args.ImageFormat);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Program.Logger.Error(ex.ToString());
|
||||||
|
Program.Logger.Error("Failed to save single frame");
|
||||||
|
}
|
||||||
|
worker?.ReportProgress(100, $"已处理 1/1");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ExportIndividual(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (FrameExportArgs)ExportArgs;
|
||||||
|
|
||||||
|
int total = spinesToRender.Length;
|
||||||
|
int success = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"已处理 0/{total}");
|
||||||
|
for (int i = 0; i < total; i++)
|
||||||
|
{
|
||||||
|
var spine = spinesToRender[i];
|
||||||
|
|
||||||
|
// 逐个导出时如果提供了输出文件夹, 则全部导出到输出文件夹, 否则输出到各自的文件夹
|
||||||
|
var filename = $"{spine.Name}_{timestamp}{args.FileSuffix}";
|
||||||
|
var savePath = args.OutputDir is null ? Path.Combine(spine.AssetsDir, filename) : Path.Combine(args.OutputDir, filename);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var frame = GetFrame(spine);
|
||||||
|
using var img = frame.CopyToBitmap();
|
||||||
|
img.SetResolution(args.DPI.Width, args.DPI.Height);
|
||||||
|
img.Save(savePath, args.ImageFormat);
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Program.Logger.Error(ex.ToString());
|
||||||
|
Program.Logger.Error("Failed to save frame {} {}", savePath, spine.SkelPath);
|
||||||
|
error++;
|
||||||
|
}
|
||||||
|
|
||||||
|
worker?.ReportProgress((int)((i + 1) * 100.0) / total, $"已处理 {i + 1}/{total}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error > 0)
|
||||||
|
Program.Logger.Warn("Frames save {} successfully, {} failed", success, error);
|
||||||
|
else
|
||||||
|
Program.Logger.Info("{} frames saved successfully", success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using SpineViewer.Exporter.Implementations.ExportArgs;
|
||||||
|
using SpineViewer.Spine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 帧序列导出器
|
||||||
|
/// </summary>
|
||||||
|
[ExportImplementation(ExportType.FrameSequence)]
|
||||||
|
public class FrameSequenceExporter : VideoExporter
|
||||||
|
{
|
||||||
|
public FrameSequenceExporter(FrameSequenceExportArgs exportArgs) : base(exportArgs) { }
|
||||||
|
|
||||||
|
protected override void ExportSingle(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (FrameSequenceExportArgs)ExportArgs;
|
||||||
|
|
||||||
|
// 导出单个时必定提供输出文件夹,
|
||||||
|
var saveDir = Path.Combine(args.OutputDir, $"frames_{timestamp}_{args.FPS:f0}");
|
||||||
|
Directory.CreateDirectory(saveDir);
|
||||||
|
|
||||||
|
int frameIdx = 0;
|
||||||
|
foreach (var frame in GetFrames(spinesToRender, worker))
|
||||||
|
{
|
||||||
|
var filename = $"frames_{timestamp}_{args.FPS:f0}_{frameIdx:d6}{args.FileSuffix}";
|
||||||
|
var savePath = Path.Combine(saveDir, filename);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
frame.SaveToFile(savePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Program.Logger.Error(ex.ToString());
|
||||||
|
Program.Logger.Error("Failed to save frame {}", savePath);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
frame.Dispose();
|
||||||
|
}
|
||||||
|
frameIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ExportIndividual(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (FrameSequenceExportArgs)ExportArgs;
|
||||||
|
foreach (var spine in spinesToRender)
|
||||||
|
{
|
||||||
|
if (worker?.CancellationPending == true) break; // 取消的日志在 GetFrames 里输出
|
||||||
|
|
||||||
|
// 如果提供了输出文件夹, 则全部导出到输出文件夹, 否则导出到各自的文件夹下
|
||||||
|
var subDir = $"{spine.Name}_{timestamp}_{args.FPS:f0}";
|
||||||
|
var saveDir = args.OutputDir is null ? Path.Combine(spine.AssetsDir, subDir) : Path.Combine(args.OutputDir, subDir);
|
||||||
|
Directory.CreateDirectory(saveDir);
|
||||||
|
|
||||||
|
int frameIdx = 0;
|
||||||
|
foreach (var frame in GetFrames(spine, worker))
|
||||||
|
{
|
||||||
|
var filename = $"{spine.Name}_{timestamp}_{args.FPS:f0}_{frameIdx:d6}{args.FileSuffix}";
|
||||||
|
var savePath = Path.Combine(saveDir, filename);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
frame.SaveToFile(savePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Program.Logger.Error(ex.ToString());
|
||||||
|
Program.Logger.Error("Failed to save frame {} {}", savePath, spine.SkelPath);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
frame.Dispose();
|
||||||
|
}
|
||||||
|
frameIdx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using SpineViewer.Exporter.Implementations.ExportArgs;
|
||||||
|
using SpineViewer.Spine;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter.Implementations.Exporter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 视频导出基类
|
||||||
|
/// </summary>
|
||||||
|
public abstract class VideoExporter : SpineViewer.Exporter.Exporter
|
||||||
|
{
|
||||||
|
public VideoExporter(VideoExportArgs exportArgs) : base(exportArgs) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成单个模型的帧序列
|
||||||
|
/// </summary>
|
||||||
|
protected IEnumerable<SFMLImageVideoFrame> GetFrames(Spine.Spine spine, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (VideoExportArgs)ExportArgs;
|
||||||
|
float delta = 1f / args.FPS;
|
||||||
|
int total = 1 + (int)(args.Duration * args.FPS); // 至少导出 1 帧
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"{spine.Name} 已处理 0/{total} 帧");
|
||||||
|
for (int i = 0; i < total; i++)
|
||||||
|
{
|
||||||
|
if (worker?.CancellationPending == true)
|
||||||
|
{
|
||||||
|
Program.Logger.Info("Export cancelled");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frame = GetFrame(spine);
|
||||||
|
spine.Update(delta);
|
||||||
|
worker?.ReportProgress((int)((i + 1) * 100.0) / total, $"{spine.Name} 已处理 {i + 1}/{total} 帧");
|
||||||
|
yield return frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成多个模型的帧序列
|
||||||
|
/// </summary>
|
||||||
|
protected IEnumerable<SFMLImageVideoFrame> GetFrames(Spine.Spine[] spinesToRender, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
var args = (VideoExportArgs)ExportArgs;
|
||||||
|
float delta = 1f / args.FPS;
|
||||||
|
int total = 1 + (int)(args.Duration * args.FPS); // 至少导出 1 帧
|
||||||
|
|
||||||
|
worker?.ReportProgress(0, $"已处理 0/{total} 帧");
|
||||||
|
for (int i = 0; i < total; i++)
|
||||||
|
{
|
||||||
|
if (worker?.CancellationPending == true)
|
||||||
|
{
|
||||||
|
Program.Logger.Info("Export cancelled");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var frame = GetFrame(spinesToRender);
|
||||||
|
foreach (var spine in spinesToRender) spine.Update(delta);
|
||||||
|
worker?.ReportProgress((int)((i + 1) * 100.0) / total, $"已处理 {i + 1}/{total} 帧");
|
||||||
|
yield return frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Export(Spine.Spine[] spines, BackgroundWorker? worker = null)
|
||||||
|
{
|
||||||
|
// 导出视频格式需要把模型时间都重置到 0
|
||||||
|
foreach (var spine in spines) spine.CurrentAnimation = spine.CurrentAnimation;
|
||||||
|
base.Export(spines, worker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
SpineViewer/Exporter/TypeConverter.cs
Normal file
33
SpineViewer/Exporter/TypeConverter.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SpineViewer.Exporter
|
||||||
|
{
|
||||||
|
public class SFMLImageFileSuffixConverter : StringConverter
|
||||||
|
{
|
||||||
|
private readonly string[] supportedFileSuffix = [".png", ".jpg", ".tga", ".bmp"];
|
||||||
|
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
|
||||||
|
{
|
||||||
|
// 支持标准值列表
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
|
||||||
|
{
|
||||||
|
// 排他模式,只有下拉列表中的值可选
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StandardValuesCollection? GetStandardValues(ITypeDescriptorContext? context)
|
||||||
|
{
|
||||||
|
return new StandardValuesCollection(supportedFileSuffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
SpineViewer/MainForm.Designer.cs
generated
94
SpineViewer/MainForm.Designer.cs
generated
@@ -36,11 +36,15 @@
|
|||||||
toolStripMenuItem_BatchOpen = new ToolStripMenuItem();
|
toolStripMenuItem_BatchOpen = new ToolStripMenuItem();
|
||||||
toolStripSeparator1 = new ToolStripSeparator();
|
toolStripSeparator1 = new ToolStripSeparator();
|
||||||
toolStripMenuItem_Export = new ToolStripMenuItem();
|
toolStripMenuItem_Export = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_ExportPreview = new ToolStripMenuItem();
|
toolStripMenuItem_ExportFrame = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportFrameSequence = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportGif = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMkv = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMp4 = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportMov = new ToolStripMenuItem();
|
||||||
|
toolStripMenuItem_ExportWebm = new ToolStripMenuItem();
|
||||||
toolStripSeparator2 = new ToolStripSeparator();
|
toolStripSeparator2 = new ToolStripSeparator();
|
||||||
toolStripMenuItem_Exit = new ToolStripMenuItem();
|
toolStripMenuItem_Exit = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_Function = new ToolStripMenuItem();
|
|
||||||
toolStripMenuItem_ResetAnimation = new ToolStripMenuItem();
|
|
||||||
toolStripMenuItem_Tool = new ToolStripMenuItem();
|
toolStripMenuItem_Tool = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_ConvertFileFormat = new ToolStripMenuItem();
|
toolStripMenuItem_ConvertFileFormat = new ToolStripMenuItem();
|
||||||
toolStripMenuItem_Download = new ToolStripMenuItem();
|
toolStripMenuItem_Download = new ToolStripMenuItem();
|
||||||
@@ -92,7 +96,7 @@
|
|||||||
//
|
//
|
||||||
menuStrip.BackColor = SystemColors.Control;
|
menuStrip.BackColor = SystemColors.Control;
|
||||||
menuStrip.ImageScalingSize = new Size(24, 24);
|
menuStrip.ImageScalingSize = new Size(24, 24);
|
||||||
menuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_File, toolStripMenuItem_Function, toolStripMenuItem_Tool, toolStripMenuItem_Download, toolStripMenuItem_Help });
|
menuStrip.Items.AddRange(new ToolStripItem[] { toolStripMenuItem_File, toolStripMenuItem_Tool, toolStripMenuItem_Download, toolStripMenuItem_Help });
|
||||||
menuStrip.Location = new Point(0, 0);
|
menuStrip.Location = new Point(0, 0);
|
||||||
menuStrip.Name = "menuStrip";
|
menuStrip.Name = "menuStrip";
|
||||||
menuStrip.Size = new Size(1748, 32);
|
menuStrip.Size = new Size(1748, 32);
|
||||||
@@ -101,7 +105,7 @@
|
|||||||
//
|
//
|
||||||
// toolStripMenuItem_File
|
// toolStripMenuItem_File
|
||||||
//
|
//
|
||||||
toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripMenuItem_ExportPreview, toolStripSeparator2, toolStripMenuItem_Exit });
|
toolStripMenuItem_File.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_Open, toolStripMenuItem_BatchOpen, toolStripSeparator1, toolStripMenuItem_Export, toolStripSeparator2, toolStripMenuItem_Exit });
|
||||||
toolStripMenuItem_File.Name = "toolStripMenuItem_File";
|
toolStripMenuItem_File.Name = "toolStripMenuItem_File";
|
||||||
toolStripMenuItem_File.Size = new Size(84, 28);
|
toolStripMenuItem_File.Size = new Size(84, 28);
|
||||||
toolStripMenuItem_File.Text = "文件(&F)";
|
toolStripMenuItem_File.Text = "文件(&F)";
|
||||||
@@ -128,18 +132,54 @@
|
|||||||
//
|
//
|
||||||
// toolStripMenuItem_Export
|
// toolStripMenuItem_Export
|
||||||
//
|
//
|
||||||
|
toolStripMenuItem_Export.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ExportFrame, toolStripMenuItem_ExportFrameSequence, toolStripMenuItem_ExportGif, toolStripMenuItem_ExportMkv, toolStripMenuItem_ExportMp4, toolStripMenuItem_ExportMov, toolStripMenuItem_ExportWebm });
|
||||||
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
|
toolStripMenuItem_Export.Name = "toolStripMenuItem_Export";
|
||||||
toolStripMenuItem_Export.ShortcutKeys = Keys.Control | Keys.S;
|
|
||||||
toolStripMenuItem_Export.Size = new Size(254, 34);
|
toolStripMenuItem_Export.Size = new Size(254, 34);
|
||||||
toolStripMenuItem_Export.Text = "导出(&E)...";
|
toolStripMenuItem_Export.Text = "导出(&E)";
|
||||||
toolStripMenuItem_Export.Click += toolStripMenuItem_Export_Click;
|
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_ExportPreview
|
// toolStripMenuItem_ExportFrame
|
||||||
//
|
//
|
||||||
toolStripMenuItem_ExportPreview.Name = "toolStripMenuItem_ExportPreview";
|
toolStripMenuItem_ExportFrame.Name = "toolStripMenuItem_ExportFrame";
|
||||||
toolStripMenuItem_ExportPreview.Size = new Size(254, 34);
|
toolStripMenuItem_ExportFrame.Size = new Size(194, 34);
|
||||||
toolStripMenuItem_ExportPreview.Text = "导出预览图(&P)...";
|
toolStripMenuItem_ExportFrame.Text = "单帧画面...";
|
||||||
toolStripMenuItem_ExportPreview.Click += toolStripMenuItem_ExportPreview_Click;
|
toolStripMenuItem_ExportFrame.Click += toolStripMenuItem_Export_Click;
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportFrameSequence
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportFrameSequence.Name = "toolStripMenuItem_ExportFrameSequence";
|
||||||
|
toolStripMenuItem_ExportFrameSequence.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportFrameSequence.Text = "帧序列...";
|
||||||
|
toolStripMenuItem_ExportFrameSequence.Click += toolStripMenuItem_Export_Click;
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportGif
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportGif.Name = "toolStripMenuItem_ExportGif";
|
||||||
|
toolStripMenuItem_ExportGif.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportGif.Text = "GIF...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMkv
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMkv.Name = "toolStripMenuItem_ExportMkv";
|
||||||
|
toolStripMenuItem_ExportMkv.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportMkv.Text = "MKV";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMp4
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMp4.Name = "toolStripMenuItem_ExportMp4";
|
||||||
|
toolStripMenuItem_ExportMp4.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportMp4.Text = "MP4...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportMov
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportMov.Name = "toolStripMenuItem_ExportMov";
|
||||||
|
toolStripMenuItem_ExportMov.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportMov.Text = "MOV...";
|
||||||
|
//
|
||||||
|
// toolStripMenuItem_ExportWebm
|
||||||
|
//
|
||||||
|
toolStripMenuItem_ExportWebm.Name = "toolStripMenuItem_ExportWebm";
|
||||||
|
toolStripMenuItem_ExportWebm.Size = new Size(194, 34);
|
||||||
|
toolStripMenuItem_ExportWebm.Text = "WebM...";
|
||||||
//
|
//
|
||||||
// toolStripSeparator2
|
// toolStripSeparator2
|
||||||
//
|
//
|
||||||
@@ -154,20 +194,6 @@
|
|||||||
toolStripMenuItem_Exit.Text = "退出(&X)";
|
toolStripMenuItem_Exit.Text = "退出(&X)";
|
||||||
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
|
toolStripMenuItem_Exit.Click += toolStripMenuItem_Exit_Click;
|
||||||
//
|
//
|
||||||
// toolStripMenuItem_Function
|
|
||||||
//
|
|
||||||
toolStripMenuItem_Function.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ResetAnimation });
|
|
||||||
toolStripMenuItem_Function.Name = "toolStripMenuItem_Function";
|
|
||||||
toolStripMenuItem_Function.Size = new Size(87, 28);
|
|
||||||
toolStripMenuItem_Function.Text = "功能(&G)";
|
|
||||||
//
|
|
||||||
// toolStripMenuItem_ResetAnimation
|
|
||||||
//
|
|
||||||
toolStripMenuItem_ResetAnimation.Name = "toolStripMenuItem_ResetAnimation";
|
|
||||||
toolStripMenuItem_ResetAnimation.Size = new Size(242, 34);
|
|
||||||
toolStripMenuItem_ResetAnimation.Text = "重置动画时间(&R)";
|
|
||||||
toolStripMenuItem_ResetAnimation.Click += toolStripMenuItem_ResetAnimation_Click;
|
|
||||||
//
|
|
||||||
// toolStripMenuItem_Tool
|
// toolStripMenuItem_Tool
|
||||||
//
|
//
|
||||||
toolStripMenuItem_Tool.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ConvertFileFormat });
|
toolStripMenuItem_Tool.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ConvertFileFormat });
|
||||||
@@ -408,7 +434,6 @@
|
|||||||
//
|
//
|
||||||
// spinePreviewer
|
// spinePreviewer
|
||||||
//
|
//
|
||||||
spinePreviewer.BackColor = SystemColors.ControlDark;
|
|
||||||
spinePreviewer.Dock = DockStyle.Fill;
|
spinePreviewer.Dock = DockStyle.Fill;
|
||||||
spinePreviewer.Location = new Point(3, 26);
|
spinePreviewer.Location = new Point(3, 26);
|
||||||
spinePreviewer.Name = "spinePreviewer";
|
spinePreviewer.Name = "spinePreviewer";
|
||||||
@@ -416,7 +441,6 @@
|
|||||||
spinePreviewer.Size = new Size(971, 850);
|
spinePreviewer.Size = new Size(971, 850);
|
||||||
spinePreviewer.SpineListView = spineListView;
|
spinePreviewer.SpineListView = spineListView;
|
||||||
spinePreviewer.TabIndex = 0;
|
spinePreviewer.TabIndex = 0;
|
||||||
spinePreviewer.MouseUp += spinePreviewer_MouseUp;
|
|
||||||
//
|
//
|
||||||
// panel_MainForm
|
// panel_MainForm
|
||||||
//
|
//
|
||||||
@@ -481,7 +505,6 @@
|
|||||||
private ToolStripMenuItem toolStripMenuItem_Open;
|
private ToolStripMenuItem toolStripMenuItem_Open;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Exit;
|
private ToolStripMenuItem toolStripMenuItem_Exit;
|
||||||
private ToolStripSeparator toolStripSeparator1;
|
private ToolStripSeparator toolStripSeparator1;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Export;
|
|
||||||
private ToolStripSeparator toolStripSeparator2;
|
private ToolStripSeparator toolStripSeparator2;
|
||||||
private RichTextBox rtbLog;
|
private RichTextBox rtbLog;
|
||||||
private SplitContainer splitContainer_MainForm;
|
private SplitContainer splitContainer_MainForm;
|
||||||
@@ -501,14 +524,19 @@
|
|||||||
private Controls.SpineListView spineListView;
|
private Controls.SpineListView spineListView;
|
||||||
private PropertyGrid propertyGrid_Previewer;
|
private PropertyGrid propertyGrid_Previewer;
|
||||||
private Controls.SpinePreviewer spinePreviewer;
|
private Controls.SpinePreviewer spinePreviewer;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Function;
|
|
||||||
private ToolStripMenuItem toolStripMenuItem_ResetAnimation;
|
|
||||||
private ToolStripMenuItem toolStripMenuItem_Diagnostics;
|
private ToolStripMenuItem toolStripMenuItem_Diagnostics;
|
||||||
private ToolStripSeparator toolStripSeparator3;
|
private ToolStripSeparator toolStripSeparator3;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Download;
|
private ToolStripMenuItem toolStripMenuItem_Download;
|
||||||
private ToolStripMenuItem toolStripMenuItem_ManageResource;
|
private ToolStripMenuItem toolStripMenuItem_ManageResource;
|
||||||
private ToolStripMenuItem toolStripMenuItem_Tool;
|
private ToolStripMenuItem toolStripMenuItem_Tool;
|
||||||
private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat;
|
private ToolStripMenuItem toolStripMenuItem_ConvertFileFormat;
|
||||||
private ToolStripMenuItem toolStripMenuItem_ExportPreview;
|
private ToolStripMenuItem toolStripMenuItem_Export;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportFrame;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportFrameSequence;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportGif;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMp4;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMov;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportMkv;
|
||||||
|
private ToolStripMenuItem toolStripMenuItem_ExportWebm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Diagnostics;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
using SpineViewer.Exporter;
|
||||||
|
|
||||||
namespace SpineViewer
|
namespace SpineViewer
|
||||||
{
|
{
|
||||||
@@ -17,6 +18,10 @@ namespace SpineViewer
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeLogConfiguration();
|
InitializeLogConfiguration();
|
||||||
|
|
||||||
|
// 在此处将导出菜单需要的类绑定起来
|
||||||
|
toolStripMenuItem_ExportFrame.Tag = ExportType.Frame;
|
||||||
|
toolStripMenuItem_ExportFrameSequence.Tag = ExportType.FrameSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -49,12 +54,12 @@ namespace SpineViewer
|
|||||||
|
|
||||||
private void MainForm_Load(object sender, EventArgs e)
|
private void MainForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
spinePreviewer.StartPreview();
|
spinePreviewer.StartRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
{
|
{
|
||||||
spinePreviewer.StopPreview();
|
spinePreviewer.StopRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_Open_Click(object sender, EventArgs e)
|
||||||
@@ -69,7 +74,14 @@ namespace SpineViewer
|
|||||||
|
|
||||||
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_Export_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
// TODO: 改成统一导出调用
|
ExportType type = (ExportType)((ToolStripMenuItem)sender).Tag;
|
||||||
|
|
||||||
|
if (type == ExportType.Frame && spinePreviewer.IsUpdating)
|
||||||
|
{
|
||||||
|
if (MessageBox.Quest("画面仍在更新,建议手动暂停画面后导出固定的一帧,是否继续?") != DialogResult.OK)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lock (spineListView.Spines)
|
lock (spineListView.Spines)
|
||||||
{
|
{
|
||||||
if (spineListView.Spines.Count <= 0)
|
if (spineListView.Spines.Count <= 0)
|
||||||
@@ -79,34 +91,16 @@ namespace SpineViewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var exportDialog = new Dialogs.ExportPngDialog();
|
var exportArgs = ExportArgs.New(type, spinePreviewer.Resolution, spinePreviewer.GetView(), spinePreviewer.RenderSelectedOnly);
|
||||||
|
var exportDialog = new Dialogs.ExportDialog() { ExportArgs = exportArgs };
|
||||||
if (exportDialog.ShowDialog() != DialogResult.OK)
|
if (exportDialog.ShowDialog() != DialogResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var progressDialog = new Dialogs.ProgressDialog();
|
var exporter = Exporter.Exporter.New(type, exportArgs);
|
||||||
progressDialog.DoWork += ExportPng_Work;
|
|
||||||
progressDialog.RunWorkerAsync(exportDialog);
|
|
||||||
progressDialog.ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void toolStripMenuItem_ExportPreview_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
lock (spineListView.Spines)
|
|
||||||
{
|
|
||||||
if (spineListView.Spines.Count <= 0)
|
|
||||||
{
|
|
||||||
MessageBox.Info("请至少打开一个骨骼文件");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveDialog = new Dialogs.ExportPreviewDialog();
|
|
||||||
if (saveDialog.ShowDialog() != DialogResult.OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var progressDialog = new Dialogs.ProgressDialog();
|
var progressDialog = new Dialogs.ProgressDialog();
|
||||||
progressDialog.DoWork += ExportPreview_Work;
|
progressDialog.DoWork += Export_Work;
|
||||||
progressDialog.RunWorkerAsync(saveDialog);
|
progressDialog.RunWorkerAsync(exporter);
|
||||||
progressDialog.ShowDialog();
|
progressDialog.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,15 +109,6 @@ namespace SpineViewer
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toolStripMenuItem_ResetAnimation_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
lock (spineListView.Spines)
|
|
||||||
{
|
|
||||||
foreach (var spine in spineListView.Spines)
|
|
||||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void toolStripMenuItem_ConvertFileFormat_Click(object sender, EventArgs e)
|
private void toolStripMenuItem_ConvertFileFormat_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var openDialog = new Dialogs.ConvertFileFormatDialog();
|
var openDialog = new Dialogs.ConvertFileFormatDialog();
|
||||||
@@ -132,7 +117,7 @@ namespace SpineViewer
|
|||||||
|
|
||||||
var progressDialog = new Dialogs.ProgressDialog();
|
var progressDialog = new Dialogs.ProgressDialog();
|
||||||
progressDialog.DoWork += ConvertFileFormat_Work;
|
progressDialog.DoWork += ConvertFileFormat_Work;
|
||||||
progressDialog.RunWorkerAsync(openDialog);
|
progressDialog.RunWorkerAsync(openDialog.Result);
|
||||||
progressDialog.ShowDialog();
|
progressDialog.ShowDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,177 +201,38 @@ namespace SpineViewer
|
|||||||
|
|
||||||
private void splitContainer_MouseUp(object sender, MouseEventArgs e) => ActiveControl = null;
|
private void splitContainer_MouseUp(object sender, MouseEventArgs e) => ActiveControl = null;
|
||||||
|
|
||||||
private void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e) => (sender as PropertyGrid)?.Refresh();
|
private void propertyGrid_PropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
|
||||||
|
|
||||||
private void spinePreviewer_MouseUp(object sender, MouseEventArgs e)
|
|
||||||
{
|
{
|
||||||
propertyGrid_Spine.Refresh();
|
// 用来解决对面板某些值修改之后, 其他被联动修改的值不会实时刷新的问题
|
||||||
|
(sender as PropertyGrid)?.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExportPng_Work(object? sender, DoWorkEventArgs e)
|
private void Export_Work(object? sender, DoWorkEventArgs e)
|
||||||
{
|
{
|
||||||
var worker = sender as BackgroundWorker;
|
var worker = (BackgroundWorker)sender;
|
||||||
var arguments = e.Argument as Dialogs.ExportPngDialog;
|
var exporter = (Exporter.Exporter)e.Argument;
|
||||||
var outputDir = arguments.OutputDir;
|
spinePreviewer.StopRender();
|
||||||
var duration = arguments.Duration;
|
lock (spineListView.Spines) { exporter.Export(spineListView.Spines.ToArray(), (BackgroundWorker)sender); }
|
||||||
var fps = arguments.Fps;
|
e.Cancel = worker.CancellationPending;
|
||||||
var timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
spinePreviewer.StartRender();
|
||||||
|
|
||||||
var frameArgs = spinePreviewer.GetFrameArgs();
|
|
||||||
var renderSelectedOnly = spinePreviewer.RenderSelectedOnly;
|
|
||||||
|
|
||||||
var resolution = frameArgs.Resolution;
|
|
||||||
var tex = new SFML.Graphics.RenderTexture((uint)resolution.Width, (uint)resolution.Height);
|
|
||||||
tex.SetView(frameArgs.View);
|
|
||||||
var delta = 1f / fps;
|
|
||||||
var frameCount = 1 + (int)(duration / delta); // 零帧开始导出
|
|
||||||
|
|
||||||
spinePreviewer.StopPreview();
|
|
||||||
|
|
||||||
lock (spineListView.Spines)
|
|
||||||
{
|
|
||||||
var spinesReverse = spineListView.Spines.Reverse();
|
|
||||||
|
|
||||||
// 重置动画时间
|
|
||||||
foreach (var spine in spinesReverse)
|
|
||||||
spine.CurrentAnimation = spine.CurrentAnimation;
|
|
||||||
|
|
||||||
Program.Logger.Info(
|
|
||||||
"Begin exporting png frames to output dir {}, duration: {}, fps: {}, totally {} spines",
|
|
||||||
[outputDir, duration, fps, spinesReverse.Count()]
|
|
||||||
);
|
|
||||||
|
|
||||||
// 逐帧导出
|
|
||||||
var success = 0;
|
|
||||||
worker.ReportProgress(0, $"已处理 0/{frameCount}");
|
|
||||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
|
||||||
{
|
|
||||||
if (worker.CancellationPending)
|
|
||||||
break;
|
|
||||||
|
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
|
||||||
|
|
||||||
foreach (var spine in spinesReverse)
|
|
||||||
{
|
|
||||||
if (renderSelectedOnly && !spine.IsSelected)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tex.Draw(spine);
|
|
||||||
spine.Update(delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
tex.Display();
|
|
||||||
using (var img = tex.Texture.CopyToImage())
|
|
||||||
{
|
|
||||||
img.SaveToFile(Path.Combine(outputDir, $"{timestamp}_{fps}_{frameIndex:d6}.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
success++;
|
|
||||||
worker.ReportProgress((int)((frameIndex + 1) * 100.0) / frameCount, $"已处理 {frameIndex + 1}/{frameCount}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Program.Logger.Info("Exporting done: {}/{}", success, frameCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
spinePreviewer.StartPreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 tex = new SFML.Graphics.RenderTexture(width, height);
|
|
||||||
|
|
||||||
int success = 0;
|
|
||||||
int error = 0;
|
|
||||||
spinePreviewer.StopPreview();
|
|
||||||
lock (spineListView.Spines)
|
|
||||||
{
|
|
||||||
var spines = spineListView.Spines;
|
|
||||||
int totalCount = spines.Count;
|
|
||||||
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
|
||||||
for (int i = 0; i < totalCount; i++)
|
|
||||||
{
|
|
||||||
if (worker.CancellationPending)
|
|
||||||
{
|
|
||||||
e.Cancel = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var spine = spines[i];
|
|
||||||
var tmp = spine.CurrentAnimation;
|
|
||||||
spine.CurrentAnimation = Spine.Spine.EMPTY_ANIMATION;
|
|
||||||
tex.SetView(spine.GetInitView(width, height, paddingL, paddingR, paddingT, paddingB));
|
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
|
||||||
tex.Draw(spine);
|
|
||||||
tex.Display();
|
|
||||||
spine.CurrentAnimation = tmp;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var img = tex.Texture.CopyToImage())
|
|
||||||
{
|
|
||||||
img.SaveToFile(Path.Combine(outputDir, $"{spine.Name}.png"));
|
|
||||||
}
|
|
||||||
success++;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Program.Logger.Error(ex.ToString());
|
|
||||||
Program.Logger.Error("Failed to save preview {}", spine.SkelPath);
|
|
||||||
error++;
|
|
||||||
}
|
|
||||||
|
|
||||||
worker.ReportProgress((int)((i + 1) * 100.0) / totalCount, $"已处理 {i + 1}/{totalCount}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spinePreviewer.StartPreview();
|
|
||||||
|
|
||||||
if (error > 0)
|
|
||||||
{
|
|
||||||
Program.Logger.Warn("Preview save {} successfully, {} failed", success, error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Program.Logger.Info("{} preview saved successfully", success);
|
|
||||||
}
|
|
||||||
|
|
||||||
Program.LogCurrentMemoryUsage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e)
|
private void ConvertFileFormat_Work(object? sender, DoWorkEventArgs e)
|
||||||
{
|
{
|
||||||
var worker = sender as BackgroundWorker;
|
var worker = sender as BackgroundWorker;
|
||||||
var arguments = e.Argument as Dialogs.ConvertFileFormatDialog;
|
var arguments = e.Argument as Dialogs.ConvertFileFormatDialogResult;
|
||||||
var skelPaths = arguments.SkelPaths;
|
var skelPaths = arguments.SkelPaths;
|
||||||
var srcVersion = arguments.SourceVersion;
|
var srcVersion = arguments.SourceVersion;
|
||||||
var tgtVersion = arguments.TargetVersion;
|
var tgtVersion = arguments.TargetVersion;
|
||||||
var jsonSource = arguments.JsonSource;
|
|
||||||
var jsonTarget = arguments.JsonTarget;
|
var jsonTarget = arguments.JsonTarget;
|
||||||
var newSuffix = jsonTarget ? ".json" : ".skel";
|
var newSuffix = jsonTarget ? ".json" : ".skel";
|
||||||
|
|
||||||
if (jsonTarget == jsonSource)
|
|
||||||
{
|
|
||||||
if (tgtVersion == srcVersion)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
newSuffix += $".{tgtVersion.ToString().ToLower()}"; // TODO: 仅转换版本的情况下考虑文件覆盖问题
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalCount = skelPaths.Length;
|
int totalCount = skelPaths.Length;
|
||||||
int success = 0;
|
int success = 0;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
SkeletonConverter srcCvter = SkeletonConverter.New(srcVersion);
|
SkeletonConverter srcCvter = srcVersion != Spine.Version.Auto ? SkeletonConverter.New(srcVersion) : null;
|
||||||
SkeletonConverter tgtCvter = tgtVersion == srcVersion ? srcCvter : SkeletonConverter.New(tgtVersion);
|
SkeletonConverter tgtCvter = SkeletonConverter.New(tgtVersion);
|
||||||
|
|
||||||
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
worker.ReportProgress(0, $"已处理 0/{totalCount}");
|
||||||
for (int i = 0; i < totalCount; i++)
|
for (int i = 0; i < totalCount; i++)
|
||||||
@@ -402,8 +248,15 @@ namespace SpineViewer
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var root = jsonSource ? srcCvter.ReadJson(skelPath) : srcCvter.ReadBinary(skelPath);
|
if (srcVersion == Spine.Version.Auto)
|
||||||
if (tgtVersion != srcVersion) root = srcCvter.ToVersion(root, tgtVersion);
|
{
|
||||||
|
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);
|
if (jsonTarget) tgtCvter.WriteJson(root, newPath); else tgtCvter.WriteBinary(root, newPath);
|
||||||
success++;
|
success++;
|
||||||
}
|
}
|
||||||
@@ -426,5 +279,28 @@ namespace SpineViewer
|
|||||||
Program.Logger.Info("{} skel converted successfully", success);
|
Program.Logger.Info("{} skel converted successfully", success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//private void spinePreviewer_KeyDown(object sender, KeyEventArgs e)
|
||||||
|
//{
|
||||||
|
// switch (e.KeyCode)
|
||||||
|
// {
|
||||||
|
// case Keys.Space:
|
||||||
|
// if ((ModifierKeys & Keys.Alt) != 0)
|
||||||
|
// spinePreviewer.ClickStopButton();
|
||||||
|
// else
|
||||||
|
// spinePreviewer.ClickStartButton();
|
||||||
|
// break;
|
||||||
|
// case Keys.Right:
|
||||||
|
// if ((ModifierKeys & Keys.Alt) != 0)
|
||||||
|
// spinePreviewer.ClickForwardFastButton();
|
||||||
|
// else
|
||||||
|
// spinePreviewer.ClickForwardStepButton();
|
||||||
|
// break;
|
||||||
|
// case Keys.Left:
|
||||||
|
// if ((ModifierKeys & Keys.Alt) != 0)
|
||||||
|
// spinePreviewer.ClickRestartButton();
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ using System.Text.Json;
|
|||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using SpineRuntime38.Attachments;
|
using SpineRuntime38.Attachments;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace SpineViewer.Spine.Implementations.SkeletonConverter
|
namespace SpineViewer.Spine.Implementations.SkeletonConverter
|
||||||
{
|
{
|
||||||
[SkeletonConverterImplementation(Version.V38)]
|
[SpineImplementation(Version.V38)]
|
||||||
class SkeletonConverter38 : SpineViewer.Spine.SkeletonConverter
|
class SkeletonConverter38 : SpineViewer.Spine.SkeletonConverter
|
||||||
{
|
{
|
||||||
private BinaryReader reader = null;
|
private BinaryReader reader = null;
|
||||||
|
|||||||
@@ -12,20 +12,6 @@ using System.Text.Encodings.Web;
|
|||||||
|
|
||||||
namespace SpineViewer.Spine
|
namespace SpineViewer.Spine
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// SkeletonConverter 实现类标记
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
|
||||||
public class SkeletonConverterImplementationAttribute : Attribute
|
|
||||||
{
|
|
||||||
public Version Version { get; }
|
|
||||||
|
|
||||||
public SkeletonConverterImplementationAttribute(Version version)
|
|
||||||
{
|
|
||||||
Version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SkeletonConverter 基类, 使用静态方法 New 来创建具体版本对象
|
/// SkeletonConverter 基类, 使用静态方法 New 来创建具体版本对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -42,11 +28,11 @@ namespace SpineViewer.Spine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static SkeletonConverter()
|
static SkeletonConverter()
|
||||||
{
|
{
|
||||||
// 遍历并缓存标记了 SkeletonConverterImplementationAttribute 的类型
|
// 遍历并缓存标记了 SpineImplementationAttribute 的类型
|
||||||
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(SkeletonConverter).IsAssignableFrom(t) && !t.IsAbstract);
|
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(SkeletonConverter).IsAssignableFrom(t) && !t.IsAbstract);
|
||||||
foreach (var type in impTypes)
|
foreach (var type in impTypes)
|
||||||
{
|
{
|
||||||
var attr = type.GetCustomAttribute<SkeletonConverterImplementationAttribute>();
|
var attr = type.GetCustomAttribute<SpineImplementationAttribute>();
|
||||||
if (attr is not null)
|
if (attr is not null)
|
||||||
{
|
{
|
||||||
if (ImplementationTypes.ContainsKey(attr.Version))
|
if (ImplementationTypes.ContainsKey(attr.Version))
|
||||||
@@ -111,6 +97,29 @@ namespace SpineViewer.Spine
|
|||||||
root.WriteTo(writer);
|
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>
|
||||||
/// 转换到目标版本
|
/// 转换到目标版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -14,23 +14,10 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using SpineViewer.Exporter;
|
||||||
|
|
||||||
namespace SpineViewer.Spine
|
namespace SpineViewer.Spine
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Spine 实现类标记
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
|
||||||
public class SpineImplementationAttribute : Attribute
|
|
||||||
{
|
|
||||||
public Version Version { get; }
|
|
||||||
|
|
||||||
public SpineImplementationAttribute(Version version)
|
|
||||||
{
|
|
||||||
Version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spine 基类, 使用静态方法 New 来创建具体版本对象
|
/// Spine 基类, 使用静态方法 New 来创建具体版本对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -346,6 +333,26 @@ namespace SpineViewer.Spine
|
|||||||
[Browsable(false)]
|
[Browsable(false)]
|
||||||
public abstract RectangleF Bounds { get; }
|
public abstract RectangleF Bounds { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始状态下的骨骼包围盒
|
||||||
|
/// </summary>
|
||||||
|
[Browsable(false)]
|
||||||
|
public RectangleF InitBounds
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (initBounds is null)
|
||||||
|
{
|
||||||
|
var tmp = CurrentAnimation;
|
||||||
|
CurrentAnimation = EMPTY_ANIMATION;
|
||||||
|
initBounds = Bounds;
|
||||||
|
CurrentAnimation = tmp;
|
||||||
|
}
|
||||||
|
return (RectangleF)initBounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private RectangleF? initBounds = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 骨骼预览图
|
/// 骨骼预览图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -362,7 +369,7 @@ namespace SpineViewer.Spine
|
|||||||
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
// 除此之外, 似乎还和 tex 的 Dispose 有关
|
||||||
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
// 如果不对 tex 进行 Dispose, 那么不管是否 Draw 都正常不会死锁
|
||||||
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
var tex = new SFML.Graphics.RenderTexture(PREVIEW_WIDTH, PREVIEW_HEIGHT);
|
||||||
tex.SetView(GetInitView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
tex.SetView(InitBounds.GetView(PREVIEW_WIDTH, PREVIEW_HEIGHT));
|
||||||
tex.Clear(SFML.Graphics.Color.Transparent);
|
tex.Clear(SFML.Graphics.Color.Transparent);
|
||||||
var tmp = CurrentAnimation;
|
var tmp = CurrentAnimation;
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
CurrentAnimation = EMPTY_ANIMATION;
|
||||||
@@ -373,7 +380,7 @@ namespace SpineViewer.Spine
|
|||||||
using var img = tex.Texture.CopyToImage();
|
using var img = tex.Texture.CopyToImage();
|
||||||
img.SaveToMemory(out var imgBuffer, "bmp");
|
img.SaveToMemory(out var imgBuffer, "bmp");
|
||||||
using var stream = new MemoryStream(imgBuffer);
|
using var stream = new MemoryStream(imgBuffer);
|
||||||
preview = new Bitmap(stream);
|
preview = new Bitmap(new Bitmap(stream)); // 必须重复构造一个副本才能摆脱对流的依赖, 否则之后使用会报错
|
||||||
}
|
}
|
||||||
return preview;
|
return preview;
|
||||||
}
|
}
|
||||||
@@ -391,53 +398,6 @@ namespace SpineViewer.Spine
|
|||||||
/// <param name="delta">时间间隔</param>
|
/// <param name="delta">时间间隔</param>
|
||||||
public abstract void Update(float delta);
|
public abstract void Update(float delta);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(Size resolution, Padding padding) =>
|
|
||||||
GetInitView((uint)resolution.Width, (uint)resolution.Height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(uint width, uint height, Padding padding) =>
|
|
||||||
GetInitView(width, height, (uint)padding.Left, (uint)padding.Right, (uint)padding.Top, (uint)padding.Bottom);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(Size resolution, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1) =>
|
|
||||||
GetInitView((uint)resolution.Width, (uint)resolution.Height, paddingL, paddingR, paddingT, paddingB);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取初始状态下合适的 View, 参数单位为像素
|
|
||||||
/// </summary>
|
|
||||||
public SFML.Graphics.View GetInitView(uint width, uint height, uint paddingL = 1, uint paddingR = 1, uint paddingT = 1, uint paddingB = 1)
|
|
||||||
{
|
|
||||||
var tmp = CurrentAnimation;
|
|
||||||
CurrentAnimation = EMPTY_ANIMATION;
|
|
||||||
var bounds = Bounds;
|
|
||||||
CurrentAnimation = tmp;
|
|
||||||
|
|
||||||
float sizeX = bounds.Width;
|
|
||||||
float sizeY = bounds.Height;
|
|
||||||
float innerW = width - paddingL - paddingR;
|
|
||||||
float innerH = height - paddingT - paddingB;
|
|
||||||
|
|
||||||
float scale = 1;
|
|
||||||
if ((sizeY / sizeX) < (innerH / innerW))
|
|
||||||
scale = sizeX / innerW; // 相同的 X, 视窗 Y 更大
|
|
||||||
else
|
|
||||||
scale = sizeY / innerH; // 相同的 Y, 视窗 X 更大
|
|
||||||
|
|
||||||
var x = bounds.X + bounds.Width / 2 + ((float)paddingL - (float)paddingR) * scale;
|
|
||||||
var y = bounds.Y + bounds.Height / 2 + ((float)paddingT - (float)paddingB) * scale;
|
|
||||||
var viewX = width * scale;
|
|
||||||
var viewY = height * scale;
|
|
||||||
|
|
||||||
return new(new(x, y), new(viewX, -viewY));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否被选中
|
/// 是否被选中
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
39
SpineViewer/Spine/UITypeEditor.cs
Normal file
39
SpineViewer/Spine/UITypeEditor.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms.Design;
|
||||||
|
|
||||||
|
namespace SpineViewer.Spine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// skel 文件路径编辑器
|
||||||
|
/// </summary>
|
||||||
|
public class SkelFileNameEditor : FileNameEditor
|
||||||
|
{
|
||||||
|
protected override void InitializeDialog(OpenFileDialog openFileDialog)
|
||||||
|
{
|
||||||
|
base.InitializeDialog(openFileDialog);
|
||||||
|
openFileDialog.Title = "选择 skel 文件";
|
||||||
|
openFileDialog.AddExtension = false;
|
||||||
|
openFileDialog.Filter = "skel 文件 (*.skel; *.json)|*.skel;*.json|二进制文件 (*.skel)|*.skel|文本文件 (*.json)|*.json|所有文件 (*.*)|*.*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// atlas 文件路径编辑器
|
||||||
|
/// </summary>
|
||||||
|
public class AtlasFileNameEditor : FileNameEditor
|
||||||
|
{
|
||||||
|
protected override void InitializeDialog(OpenFileDialog openFileDialog)
|
||||||
|
{
|
||||||
|
base.InitializeDialog(openFileDialog);
|
||||||
|
openFileDialog.Title = "选择 atlas 文件";
|
||||||
|
openFileDialog.AddExtension = false;
|
||||||
|
openFileDialog.Filter = "atlas 文件 (*.atlas)|*.atlas|所有文件 (*.*)|*.*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,36 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SpineViewer.Spine
|
namespace SpineViewer.Spine
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 支持的 Spine 版本
|
||||||
|
/// </summary>
|
||||||
|
public enum Version
|
||||||
|
{
|
||||||
|
[Description("<Auto>")] Auto = 0x0000,
|
||||||
|
[Description("2.1.x")] V21 = 0x0201,
|
||||||
|
[Description("3.6.x")] V36 = 0x0306,
|
||||||
|
[Description("3.7.x")] V37 = 0x0307,
|
||||||
|
[Description("3.8.x")] V38 = 0x0308,
|
||||||
|
[Description("4.0.x")] V40 = 0x0400,
|
||||||
|
[Description("4.1.x")] V41 = 0x0401,
|
||||||
|
[Description("4.2.x")] V42 = 0x0402,
|
||||||
|
[Description("4.3.x")] V43 = 0x0403,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spine 实现类标记
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class SpineImplementationAttribute : Attribute
|
||||||
|
{
|
||||||
|
public Version Version { get; }
|
||||||
|
|
||||||
|
public SpineImplementationAttribute(Version version)
|
||||||
|
{
|
||||||
|
Version = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spine 版本静态辅助类
|
/// Spine 版本静态辅助类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -61,20 +91,4 @@ namespace SpineViewer.Spine
|
|||||||
return runtimes.TryGetValue(version, out var val) ? val : GetName(version);
|
return runtimes.TryGetValue(version, out var val) ? val : GetName(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 支持的 Spine 版本
|
|
||||||
/// </summary>
|
|
||||||
public enum Version
|
|
||||||
{
|
|
||||||
[Description("<Auto>")] Auto = 0x0000,
|
|
||||||
[Description("2.1.x")] V21 = 0x0201,
|
|
||||||
[Description("3.6.x")] V36 = 0x0306,
|
|
||||||
[Description("3.7.x")] V37 = 0x0307,
|
|
||||||
[Description("3.8.x")] V38 = 0x0308,
|
|
||||||
[Description("4.0.x")] V40 = 0x0400,
|
|
||||||
[Description("4.1.x")] V41 = 0x0401,
|
|
||||||
[Description("4.2.x")] V42 = 0x0402,
|
|
||||||
[Description("4.3.x")] V43 = 0x0403,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
<Version>0.10.7</Version>
|
<Version>0.11.0</Version>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ApplicationIcon>appicon.ico</ApplicationIcon>
|
<ApplicationIcon>appicon.ico</ApplicationIcon>
|
||||||
|
<GenerateResourceWarnOnBinaryFormatterUse>false</GenerateResourceWarnOnBinaryFormatterUse>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace SpineViewer
|
namespace SpineViewer
|
||||||
{
|
{
|
||||||
public class PointFConverter : ExpandableObjectConverter
|
public class PointFConverter : TypeConverter
|
||||||
{
|
{
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
|
public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
|
||||||
{
|
{
|
||||||
|
|||||||
38
SpineViewer/UITypeEditor.cs
Normal file
38
SpineViewer/UITypeEditor.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing.Design;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms.Design;
|
||||||
|
|
||||||
|
namespace SpineViewer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用 FolderBrowserDialog 的文件夹路径编辑器
|
||||||
|
/// </summary>
|
||||||
|
public class FolderNameEditor : UITypeEditor
|
||||||
|
{
|
||||||
|
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext? context)
|
||||||
|
{
|
||||||
|
// 指定编辑风格为 Modal 对话框, 提供右边用来点击的按钮
|
||||||
|
return UITypeEditorEditStyle.Modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object? EditValue(ITypeDescriptorContext? context, IServiceProvider provider, object? value)
|
||||||
|
{
|
||||||
|
// 重写 EditValue 方法,提供自定义的文件夹选择对话框逻辑
|
||||||
|
using var dialog = new FolderBrowserDialog();
|
||||||
|
|
||||||
|
// 如果当前值为有效路径,则设置为初始选中路径
|
||||||
|
if (value is string currentPath && Directory.Exists(currentPath))
|
||||||
|
dialog.SelectedPath = currentPath;
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == DialogResult.OK)
|
||||||
|
value = dialog.SelectedPath;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user