diff --git a/SpineViewer/Controls/SpinePreviewer.Designer.cs b/SpineViewer/Controls/SpinePreviewer.Designer.cs index b62a281..8ba3bd3 100644 --- a/SpineViewer/Controls/SpinePreviewer.Designer.cs +++ b/SpineViewer/Controls/SpinePreviewer.Designer.cs @@ -29,12 +29,21 @@ private void InitializeComponent() { panel = new Panel(); + tableLayoutPanel1 = new TableLayoutPanel(); + panel_Container = new Panel(); + flowLayoutPanel1 = new FlowLayoutPanel(); + button_Stop = new Button(); + button_Start = new Button(); + button_Pause = new Button(); + tableLayoutPanel1.SuspendLayout(); + panel_Container.SuspendLayout(); + flowLayoutPanel1.SuspendLayout(); SuspendLayout(); // // panel // panel.BackColor = SystemColors.ControlDarkDark; - panel.Location = new Point(160, 160); + panel.Location = new Point(143, 124); panel.Margin = new Padding(0); panel.Name = "panel"; panel.Size = new Size(320, 320); @@ -44,20 +53,100 @@ panel.MouseUp += panel_MouseUp; 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, 596); + 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_Start); + flowLayoutPanel1.Controls.Add(button_Pause); + flowLayoutPanel1.Location = new Point(143, 596); + flowLayoutPanel1.Margin = new Padding(0); + flowLayoutPanel1.Name = "flowLayoutPanel1"; + flowLayoutPanel1.Size = new Size(354, 40); + flowLayoutPanel1.TabIndex = 1; + // + // button_Stop + // + button_Stop.Location = new Point(3, 3); + button_Stop.Name = "button_Stop"; + button_Stop.Size = new Size(112, 34); + button_Stop.TabIndex = 0; + button_Stop.Text = "停止"; + button_Stop.UseVisualStyleBackColor = true; + button_Stop.Click += button_Stop_Click; + // + // button_Start + // + button_Start.Location = new Point(121, 3); + button_Start.Name = "button_Start"; + button_Start.Size = new Size(112, 34); + button_Start.TabIndex = 1; + button_Start.Text = "开始"; + button_Start.UseVisualStyleBackColor = true; + button_Start.Click += button_Start_Click; + // + // button_Pause + // + button_Pause.Location = new Point(239, 3); + button_Pause.Name = "button_Pause"; + button_Pause.Size = new Size(112, 34); + button_Pause.TabIndex = 2; + button_Pause.Text = "暂停"; + button_Pause.UseVisualStyleBackColor = true; + button_Pause.Click += button_Pause_Click; + // // SpinePreviewer // AutoScaleDimensions = new SizeF(11F, 24F); AutoScaleMode = AutoScaleMode.Font; - BackColor = SystemColors.ControlDark; - Controls.Add(panel); + Controls.Add(tableLayoutPanel1); Name = "SpinePreviewer"; - Size = new Size(640, 640); + Size = new Size(641, 636); SizeChanged += SpinePreviewer_SizeChanged; + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + panel_Container.ResumeLayout(false); + flowLayoutPanel1.ResumeLayout(false); ResumeLayout(false); } #endregion private Panel panel; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel_Container; + private FlowLayoutPanel flowLayoutPanel1; + private Button button_Stop; + private Button button_Start; + private Button button_Pause; } } diff --git a/SpineViewer/Controls/SpinePreviewer.cs b/SpineViewer/Controls/SpinePreviewer.cs index 2791bc9..5f298d9 100644 --- a/SpineViewer/Controls/SpinePreviewer.cs +++ b/SpineViewer/Controls/SpinePreviewer.cs @@ -15,6 +15,45 @@ namespace SpineViewer.Controls { public partial class SpinePreviewer : UserControl { + /// + /// 画面拖放对象世界坐标源点 + /// + private SFML.System.Vector2f? draggingSrc = null; + + /// + /// 要绑定的 Spine 列表控件 + /// + [Category("自定义"), Description("相关联的 SpineListView")] + public SpineListView? SpineListView { get; set; } + + /// + /// 属性信息面板 + /// + [Category("自定义"), Description("用于显示画面属性的属性页")] + public PropertyGrid? PropertyGrid + { + get => propertyGrid; + set + { + propertyGrid = value; + if (propertyGrid is not null) + propertyGrid.SelectedObject = new PreviewerProperty(this); + } + } + private PropertyGrid? propertyGrid; + + #region 画面参数 + + /// + /// 画面缩放最大值 + /// + public const float ZOOM_MAX = 1000f; + + /// + /// 画面缩放最小值 + /// + public const float ZOOM_MIN = 0.001f; + /// /// 包装类, 用于属性面板显示 /// @@ -50,74 +89,6 @@ namespace SpineViewer.Controls public uint MaxFps { get => previewer.MaxFps; set => previewer.MaxFps = value; } } - /// - /// 要绑定的 Spine 列表控件 - /// - [Category("自定义"), Description("相关联的 SpineListView")] - public SpineListView? SpineListView { get; set; } - - /// - /// 属性信息面板 - /// - [Category("自定义"), Description("用于显示画面属性的属性页")] - public PropertyGrid? PropertyGrid - { - get => propertyGrid; - set - { - propertyGrid = value; - if (propertyGrid is not null) - propertyGrid.SelectedObject = new PreviewerProperty(this); - } - } - private PropertyGrid? propertyGrid; - - /// - /// 画面缩放最大值 - /// - public const float ZOOM_MAX = 1000f; - - /// - /// 画面缩放最小值 - /// - public const float ZOOM_MIN = 0.001f; - - /// - /// 预览画面背景色 - /// - private static readonly SFML.Graphics.Color BackgroundColor = new(105, 105, 105); - - /// - /// 预览画面坐标轴颜色 - /// - private static readonly SFML.Graphics.Color AxisColor = new(220, 220, 220); - - /// - /// 坐标轴顶点缓冲区 - /// - private readonly SFML.Graphics.VertexArray AxisVertex = new(SFML.Graphics.PrimitiveType.Lines, 2); - - /// - /// 渲染窗口 - /// - private readonly SFML.Graphics.RenderWindow RenderWindow; - - /// - /// 帧间隔计时器 - /// - private readonly SFML.System.Clock Clock = new(); - - /// - /// 画面拖放对象世界坐标源点 - /// - private SFML.System.Vector2f? draggingSrc = null; - - /// - /// 渲染任务 - /// - private Task? task = null; - private CancellationTokenSource? cancelToken = null; - /// /// 分辨率 /// @@ -280,6 +251,8 @@ namespace SpineViewer.Controls public uint MaxFps { get => maxFps; set { RenderWindow.SetFramerateLimit(value); maxFps = value; } } private uint maxFps = 60; + #endregion + public SpinePreviewer() { InitializeComponent(); @@ -294,14 +267,27 @@ namespace SpineViewer.Controls } /// - /// 预览画面帧参数 + /// 预览画面帧参数, TODO: 转移到统一导出参数 /// public SpinePreviewerFrameArgs GetFrameArgs() => new(Resolution, RenderWindow.GetView(), RenderSelectedOnly); + #region 渲染线程管理 + /// - /// 开始预览 + /// 渲染窗口 /// - public void StartPreview() + private readonly SFML.Graphics.RenderWindow RenderWindow; + + /// + /// 渲染任务 + /// + private Task? task = null; + private CancellationTokenSource? cancelToken = null; + + /// + /// 开始渲染 + /// + public void StartRender() { if (task is not null) return; @@ -310,9 +296,9 @@ namespace SpineViewer.Controls } /// - /// 停止预览 + /// 停止渲染 /// - public void StopPreview() + public void StopRender() { if (task is null || cancelToken is null) return; @@ -322,6 +308,56 @@ namespace SpineViewer.Controls task = null; } + #endregion + + /// + /// 是否还在更新画面 + /// + public bool IsUpdating { get; private set; } = true; + + /// + /// 开始更新 + /// + public void StartUpdate() => IsUpdating = true; + + /// + /// 暂停更新 + /// + public void PauseUpdate() => IsUpdating = false; + + /// + /// 停止更新, 将所有模型动画时间重置到 0 时刻 + /// + public void StopUpdate() + { + IsUpdating = false; + lock (SpineListView.Spines) + { + foreach (var spine in SpineListView.Spines) + spine.CurrentAnimation = spine.CurrentAnimation; + } + } + + /// + /// 预览画面背景色 + /// + private static readonly SFML.Graphics.Color BackgroundColor = new(105, 105, 105); + + /// + /// 预览画面坐标轴颜色 + /// + private static readonly SFML.Graphics.Color AxisColor = new(220, 220, 220); + + /// + /// 坐标轴顶点缓冲区 + /// + private readonly SFML.Graphics.VertexArray AxisVertex = new(SFML.Graphics.PrimitiveType.Lines, 2); + + /// + /// 帧间隔计时器 + /// + private readonly SFML.System.Clock Clock = new(); + /// /// 渲染任务 /// @@ -362,7 +398,8 @@ namespace SpineViewer.Controls break; // 提前中止 var spine = spines[i]; - spine.Update(delta); + + spine.Update(IsUpdating ? delta : 0); if (RenderSelectedOnly && !spine.IsSelected) continue; @@ -388,8 +425,8 @@ namespace SpineViewer.Controls if (RenderWindow is null) return; - float parentX = Width; - float parentY = Height; + float parentX = panel.Parent.Width; + float parentY = panel.Parent.Height; float sizeX = panel.Width; float sizeY = panel.Height; @@ -538,6 +575,21 @@ namespace SpineViewer.Controls Zoom *= (e.Delta > 0 ? 1.1f : 0.9f); PropertyGrid?.Refresh(); } + + private void button_Stop_Click(object sender, EventArgs e) + { + StopUpdate(); + } + + private void button_Start_Click(object sender, EventArgs e) + { + StartUpdate(); + } + + private void button_Pause_Click(object sender, EventArgs e) + { + PauseUpdate(); + } } /// diff --git a/SpineViewer/MainForm.Designer.cs b/SpineViewer/MainForm.Designer.cs index 8953ec0..476d91f 100644 --- a/SpineViewer/MainForm.Designer.cs +++ b/SpineViewer/MainForm.Designer.cs @@ -39,8 +39,6 @@ toolStripMenuItem_ExportPreview = new ToolStripMenuItem(); toolStripSeparator2 = new ToolStripSeparator(); toolStripMenuItem_Exit = new ToolStripMenuItem(); - toolStripMenuItem_Function = new ToolStripMenuItem(); - toolStripMenuItem_ResetAnimation = new ToolStripMenuItem(); toolStripMenuItem_Tool = new ToolStripMenuItem(); toolStripMenuItem_ConvertFileFormat = new ToolStripMenuItem(); toolStripMenuItem_Download = new ToolStripMenuItem(); @@ -92,7 +90,7 @@ // menuStrip.BackColor = SystemColors.Control; 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.Name = "menuStrip"; menuStrip.Size = new Size(1748, 32); @@ -154,20 +152,6 @@ toolStripMenuItem_Exit.Text = "退出(&X)"; 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.DropDownItems.AddRange(new ToolStripItem[] { toolStripMenuItem_ConvertFileFormat }); @@ -178,7 +162,7 @@ // toolStripMenuItem_ConvertFileFormat // toolStripMenuItem_ConvertFileFormat.Name = "toolStripMenuItem_ConvertFileFormat"; - toolStripMenuItem_ConvertFileFormat.Size = new Size(254, 34); + toolStripMenuItem_ConvertFileFormat.Size = new Size(270, 34); toolStripMenuItem_ConvertFileFormat.Text = "转换文件格式(&C)..."; toolStripMenuItem_ConvertFileFormat.Click += toolStripMenuItem_ConvertFileFormat_Click; // @@ -408,7 +392,6 @@ // // spinePreviewer // - spinePreviewer.BackColor = SystemColors.ControlDark; spinePreviewer.Dock = DockStyle.Fill; spinePreviewer.Location = new Point(3, 26); spinePreviewer.Name = "spinePreviewer"; @@ -501,8 +484,6 @@ private Controls.SpineListView spineListView; private PropertyGrid propertyGrid_Previewer; private Controls.SpinePreviewer spinePreviewer; - private ToolStripMenuItem toolStripMenuItem_Function; - private ToolStripMenuItem toolStripMenuItem_ResetAnimation; private ToolStripMenuItem toolStripMenuItem_Diagnostics; private ToolStripSeparator toolStripSeparator3; private ToolStripMenuItem toolStripMenuItem_Download; diff --git a/SpineViewer/MainForm.cs b/SpineViewer/MainForm.cs index e1c5095..f75f145 100644 --- a/SpineViewer/MainForm.cs +++ b/SpineViewer/MainForm.cs @@ -115,15 +115,6 @@ namespace SpineViewer 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) { var openDialog = new Dialogs.ConvertFileFormatDialog();