Merge pull request #118 from ww-rm/dev/wpf

v0.16.4
This commit is contained in:
ww-rm
2025-10-03 23:50:05 +08:00
committed by GitHub
45 changed files with 1777 additions and 850 deletions

View File

@@ -1,5 +1,12 @@
# CHANGELOG # CHANGELOG
## v0.16.4
- 增加 apng 导出格式
- 增加颜色拾取器面板
- 增加程序皮肤(主题颜色)首选项
- 优化部分使用体验
## v0.16.3 ## v0.16.3
- 修复加载工作区时的顺序错误 - 修复加载工作区时的顺序错误

View File

@@ -28,6 +28,7 @@ namespace Spine.Exporters
{ {
Gif, Gif,
Webp, Webp,
Apng,
Mp4, Mp4,
Webm, Webm,
Mkv, Mkv,
@@ -41,31 +42,37 @@ namespace Spine.Exporters
private VideoFormat _format = VideoFormat.Mp4; private VideoFormat _format = VideoFormat.Mp4;
/// <summary> /// <summary>
/// 动图是否循环 [Gif/Webp] /// [Gif/Webp/Apng] 动图是否循环
/// </summary> /// </summary>
public bool Loop { get => _loop; set => _loop = value; } public bool Loop { get => _loop; set => _loop = value; }
private bool _loop = true; private bool _loop = true;
/// <summary> /// <summary>
/// 质量 [Webp] /// [Webp] 质量
/// </summary> /// </summary>
public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); } public int Quality { get => _quality; set => _quality = Math.Clamp(value, 0, 100); }
private int _quality = 75; private int _quality = 75;
/// <summary> /// <summary>
/// 无损压缩 [Webp] /// [Webp] 无损压缩
/// </summary> /// </summary>
public bool Lossless { get => _lossless; set => _lossless = value; } public bool Lossless { get => _lossless; set => _lossless = value; }
private bool _lossless = false; private bool _lossless = false;
/// <summary> /// <summary>
/// CRF [Mp4/Webm/Mkv] /// [Apng] 预测器算法, 取值范围 0-5, 分别对应 none, sub, up, avg, paeth, mixed
/// </summary>
public int ApngPred { get => _apngPred; set => _apngPred = Math.Clamp(value, 0, 5); }
private int _apngPred = 5;
/// <summary>
/// [Mp4/Webm/Mkv] CRF
/// </summary> /// </summary>
public int Crf { get => _crf; set => _crf = Math.Clamp(value, 0, 63); } public int Crf { get => _crf; set => _crf = Math.Clamp(value, 0, 63); }
private int _crf = 23; private int _crf = 23;
/// <summary> /// <summary>
/// prores_ks 编码器的配置等级, -1 是自动, 越高质量越好, 只有 4 及以上才有透明通道 [Mov] /// [Mov] prores_ks 编码器的配置等级, -1 是自动, 越高质量越好, 只有 4 及以上才有透明通道
/// </summary> /// </summary>
public int Profile { get => _profile; set => _profile = Math.Clamp(value, -1, 5); } public int Profile { get => _profile; set => _profile = Math.Clamp(value, -1, 5); }
private int _profile = 5; private int _profile = 5;
@@ -93,6 +100,7 @@ namespace Spine.Exporters
{ {
VideoFormat.Gif => SetGifOptions, VideoFormat.Gif => SetGifOptions,
VideoFormat.Webp => SetWebpOptions, VideoFormat.Webp => SetWebpOptions,
VideoFormat.Apng => SetApngOptions,
VideoFormat.Mp4 => SetMp4Options, VideoFormat.Mp4 => SetMp4Options,
VideoFormat.Webm => SetWebmOptions, VideoFormat.Webm => SetWebmOptions,
VideoFormat.Mkv => SetMkvOptions, VideoFormat.Mkv => SetMkvOptions,
@@ -132,6 +140,13 @@ namespace Spine.Exporters
.WithCustomArgument(customArgs); .WithCustomArgument(customArgs);
} }
private void SetApngOptions(FFMpegArgumentOptions options)
{
var customArgs = $"-vf unpremultiply=inplace=1 -plays {(_loop ? 0 : 1)} -pred {_apngPred}";
options.ForceFormat("apng").WithVideoCodec("apng").ForcePixelFormat("rgba")
.WithCustomArgument(customArgs);
}
private void SetMp4Options(FFMpegArgumentOptions options) private void SetMp4Options(FFMpegArgumentOptions options)
{ {
// XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式 // XXX: windows 默认播放器在播放 MP4 格式时对于 libx264 编码器只支持 yuv420p 的像素格式

View File

@@ -7,7 +7,7 @@
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath> <BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.16.3</Version> <Version>0.16.4</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View File

@@ -1,4 +1,5 @@
using NLog; using NLog;
using Spine.Interfaces;
using Spine.Interfaces.Attachments; using Spine.Interfaces.Attachments;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,7 +7,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Spine.Interfaces namespace Spine
{ {
/// <summary> /// <summary>
/// 命中测试等级枚举值 /// 命中测试等级枚举值
@@ -136,7 +137,7 @@ namespace Spine.Interfaces
if (HitTestLevel == HitTestLevel.None || HitTestLevel == HitTestLevel.Bounds) if (HitTestLevel == HitTestLevel.None || HitTestLevel == HitTestLevel.Bounds)
{ {
self.GetBounds(out var bx, out var by, out var bw, out var bh); self.GetBounds(out var bx, out var by, out var bw, out var bh);
return x >= bx && x <= (bx + bw) && y >= by && y <= (by + bh); return x >= bx && x <= bx + bw && y >= by && y <= by + bh;
} }
else if (HitTestLevel == HitTestLevel.Meshes || HitTestLevel == HitTestLevel.Pixels) else if (HitTestLevel == HitTestLevel.Meshes || HitTestLevel == HitTestLevel.Pixels)
{ {
@@ -179,7 +180,7 @@ namespace Spine.Interfaces
float c2 = Cross(x2, y2, x0, y0); float c2 = Cross(x2, y2, x0, y0);
// 判断是否全部同号 (或为 0, 点在边上) // 判断是否全部同号 (或为 0, 点在边上)
if ((c0 >= 0 && c1 >= 0 && c2 >= 0) || (c0 <= 0 && c1 <= 0 && c2 <= 0)) if (c0 >= 0 && c1 >= 0 && c2 >= 0 || c0 <= 0 && c1 <= 0 && c2 <= 0)
{ {
if (HitTestLevel == HitTestLevel.Meshes) if (HitTestLevel == HitTestLevel.Meshes)
return true; return true;
@@ -229,7 +230,7 @@ namespace Spine.Interfaces
if (HitTestLevel == HitTestLevel.None) if (HitTestLevel == HitTestLevel.None)
{ {
self.GetBounds(out var bx, out var by, out var bw, out var bh); self.GetBounds(out var bx, out var by, out var bw, out var bh);
return x >= bx && x <= (bx + bw) && y >= by && y <= (by + bh); return x >= bx && x <= bx + bw && y >= by && y <= by + bh;
} }
bool hit = false; bool hit = false;

View File

@@ -8,28 +8,11 @@
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
<ResourceDictionary Source="/Resources/Geometries.xaml"/> <ResourceDictionary Source="/Resources/Geometries.xaml"/>
<ResourceDictionary Source="/Resources/Strings/zh.xaml"/> <ResourceDictionary Source="/Resources/Strings/zh.xaml"/>
<ResourceDictionary Source="/Resources/Skins/Light.xaml"/>
<ResourceDictionary Source="/Resources/Theme.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<Style x:Key="MyToggleButton" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ToggleButtonSwitch}">
<Setter Property="hc:VisualElement.HighlightBrush" Value="{StaticResource DarkSuccessBrush}"/>
</Style>
<Style TargetType="{x:Type ListBox}" BasedOn="{StaticResource ListBoxBaseStyle}">
<Setter Property="SelectionMode" Value="Extended"/>
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="False"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Visible"/>
</Style>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource ListViewBaseStyle}">
<Setter Property="SelectionMode" Value="Extended"/>
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
</Style>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@@ -1,6 +1,7 @@
using Microsoft.Win32; using Microsoft.Win32;
using NLog; using NLog;
using SpineViewer.Natives; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.ViewModels.MainWindow; using SpineViewer.ViewModels.MainWindow;
using SpineViewer.Views; using SpineViewer.Views;
using System.Collections.Frozen; using System.Collections.Frozen;
@@ -12,6 +13,7 @@ using System.IO;
using System.IO.Pipes; using System.IO.Pipes;
using System.Reflection; using System.Reflection;
using System.Windows; using System.Windows;
using System.Windows.Interop;
namespace SpineViewer namespace SpineViewer
{ {
@@ -231,8 +233,8 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to query autorun registry key, {0}", ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to query autorun registry key, {0}", ex.Message);
return false; return false;
} }
} }
@@ -259,8 +261,8 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to set autorun registry key, {0}", ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to set autorun registry key, {0}", ex.Message);
} }
} }
} }
@@ -343,12 +345,36 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
} }
} }
} }
private AppLanguage _language = AppLanguage.ZH; private AppLanguage _language = AppLanguage.ZH;
public AppSkin Skin
{
get => _skin;
set
{
var uri = $"Resources/Skins/{value.ToString().ToLower()}.xaml";
try
{
Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) });
Resources.MergedDictionaries.Add(new() { Source = new("Resources/Theme.xaml", UriKind.Relative) });
var hwnd = new WindowInteropHelper(Current.MainWindow).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
_skin = value;
}
catch (Exception ex)
{
_logger.Trace(ex.ToString());
_logger.Error("Failed to switch skin to {0}, {1}", value, ex.Message);
}
}
}
private AppSkin _skin = AppSkin.Light;
} }
public enum AppLanguage public enum AppLanguage
@@ -357,4 +383,11 @@ namespace SpineViewer
EN, EN,
JA JA
} }
public enum AppSkin
{
Light,
Dark,
Violet,
}
} }

View File

@@ -1,5 +1,4 @@
using Spine; using Spine;
using Spine.Interfaces;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

View File

@@ -1,6 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Spine.Interfaces; using Spine;
using SpineViewer.Services; using SpineViewer.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -86,6 +86,9 @@ namespace SpineViewer.Models
[ObservableProperty] [ObservableProperty]
private AppLanguage _appLanguage; private AppLanguage _appLanguage;
[ObservableProperty]
private AppSkin _appSkin;
[ObservableProperty] [ObservableProperty]
private bool _renderSelectedOnly; private bool _renderSelectedOnly;

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace SpineViewer.Natives
{
/// <summary>
/// dwmapi.dll 包装类
/// </summary>
public static class Dwmapi
{
private const uint DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
private const uint DWMWA_CAPTION_COLOR = 35;
private const uint DWMWA_TEXT_COLOR = 36;
private const uint DWMWA_COLOR_DEFAULT = 0xFFFFFFFF;
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, ref int pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, ref uint pvAttribute, int cbAttribute);
public static bool SetWindowCaptionColor(IntPtr hwnd, Color color)
{
int c = color.R | (color.G << 8) | (color.B << 16);
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, ref c, sizeof(uint));
}
public static bool SetWindowTextColor(IntPtr hwnd, Color color)
{
int c = color.R | (color.G << 8) | (color.B << 16);
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, ref c, sizeof(uint));
}
public static bool SetWindowDarkMode(IntPtr hwnd, bool darkMode)
{
int b = darkMode ? 1 : 0;
uint c = DWMWA_COLOR_DEFAULT;
DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, ref c, sizeof(uint));
DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, ref c, sizeof(uint));
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, ref b, sizeof(int));
}
}
}

View File

@@ -12,7 +12,102 @@ namespace SpineViewer.Resources
/// </summary> /// </summary>
public static class AppResource public static class AppResource
{ {
public static T Get<T>(string key) => (T)App.Current.FindResource(key); private static T Get<T>(string key) => (T)App.Current.FindResource(key);
#region Colors
public static Color Color_LightPrimary => Get<Color>("LightPrimaryColor");
public static Color Color_Primary => Get<Color>("PrimaryColor");
public static Color Color_DarkPrimary => Get<Color>("DarkPrimaryColor");
public static Color Color_LightDanger => Get<Color>("LightDangerColor");
public static Color Color_Danger => Get<Color>("DangerColor");
public static Color Color_DarkDanger => Get<Color>("DarkDangerColor");
public static Color Color_LightWarning => Get<Color>("LightWarningColor");
public static Color Color_Warning => Get<Color>("WarningColor");
public static Color Color_DarkWarning => Get<Color>("DarkWarningColor");
public static Color Color_LightInfo => Get<Color>("LightInfoColor");
public static Color Color_Info => Get<Color>("InfoColor");
public static Color Color_DarkInfo => Get<Color>("DarkInfoColor");
public static Color Color_LightSuccess => Get<Color>("LightSuccessColor");
public static Color Color_Success => Get<Color>("SuccessColor");
public static Color Color_DarkSuccess => Get<Color>("DarkSuccessColor");
public static Color Color_PrimaryText => Get<Color>("PrimaryTextColor");
public static Color Color_SecondaryText => Get<Color>("SecondaryTextColor");
public static Color Color_ThirdlyText => Get<Color>("ThirdlyTextColor");
public static Color Color_ReverseText => Get<Color>("ReverseTextColor");
public static Color Color_TextIcon => Get<Color>("TextIconColor");
public static Color Color_Border => Get<Color>("BorderColor");
public static Color Color_SecondaryBorder => Get<Color>("SecondaryBorderColor");
public static Color Color_Background => Get<Color>("BackgroundColor");
public static Color Color_Region => Get<Color>("RegionColor");
public static Color Color_SecondaryRegion => Get<Color>("SecondaryRegionColor");
public static Color Color_ThirdlyRegion => Get<Color>("ThirdlyRegionColor");
public static Color Color_Title => Get<Color>("TitleColor");
public static Color Color_SecondaryTitle => Get<Color>("SecondaryTitleColor");
public static Color Color_Default => Get<Color>("DefaultColor");
public static Color Color_DarkDefault => Get<Color>("DarkDefaultColor");
public static Color Color_Accent => Get<Color>("AccentColor");
public static Color Color_DarkAccent => Get<Color>("DarkAccentColor");
public static Color Color_DarkMask => Get<Color>("DarkMaskColor");
public static Color Color_DarkOpacity => Get<Color>("DarkOpacityColor");
#endregion
#region Brushes
public static SolidColorBrush Brush_LightPrimary => Get<SolidColorBrush>("LightPrimaryBrush");
public static LinearGradientBrush Brush_Primary => Get<LinearGradientBrush>("PrimaryBrush");
public static SolidColorBrush Brush_DarkPrimary => Get<SolidColorBrush>("DarkPrimaryBrush");
public static SolidColorBrush Brush_PrimaryText => Get<SolidColorBrush>("PrimaryTextBrush");
public static SolidColorBrush Brush_SecondaryText => Get<SolidColorBrush>("SecondaryTextBrush");
public static SolidColorBrush Brush_ThirdlyText => Get<SolidColorBrush>("ThirdlyTextBrush");
public static SolidColorBrush Brush_ReverseText => Get<SolidColorBrush>("ReverseTextBrush");
public static SolidColorBrush Brush_TextIcon => Get<SolidColorBrush>("TextIconBrush");
public static SolidColorBrush Brush_Border => Get<SolidColorBrush>("BorderBrush");
public static SolidColorBrush Brush_SecondaryBorder => Get<SolidColorBrush>("SecondaryBorderBrush");
public static SolidColorBrush Brush_Background => Get<SolidColorBrush>("BackgroundBrush");
public static SolidColorBrush Brush_Region => Get<SolidColorBrush>("RegionBrush");
public static SolidColorBrush Brush_SecondaryRegion => Get<SolidColorBrush>("SecondaryRegionBrush");
public static SolidColorBrush Brush_ThirdlyRegion => Get<SolidColorBrush>("ThirdlyRegionBrush");
public static LinearGradientBrush Brush_Title => Get<LinearGradientBrush>("TitleBrush");
public static SolidColorBrush Brush_Default => Get<SolidColorBrush>("DefaultBrush");
public static SolidColorBrush Brush_DarkDefault => Get<SolidColorBrush>("DarkDefaultBrush");
public static SolidColorBrush Brush_LightDanger => Get<SolidColorBrush>("LightDangerBrush");
public static LinearGradientBrush Brush_Danger => Get<LinearGradientBrush>("DangerBrush");
public static SolidColorBrush Brush_DarkDanger => Get<SolidColorBrush>("DarkDangerBrush");
public static SolidColorBrush Brush_LightWarning => Get<SolidColorBrush>("LightWarningBrush");
public static LinearGradientBrush Brush_Warning => Get<LinearGradientBrush>("WarningBrush");
public static SolidColorBrush Brush_DarkWarning => Get<SolidColorBrush>("DarkWarningBrush");
public static SolidColorBrush Brush_LightInfo => Get<SolidColorBrush>("LightInfoBrush");
public static LinearGradientBrush Brush_Info => Get<LinearGradientBrush>("InfoBrush");
public static SolidColorBrush Brush_DarkInfo => Get<SolidColorBrush>("DarkInfoBrush");
public static SolidColorBrush Brush_LightSuccess => Get<SolidColorBrush>("LightSuccessBrush");
public static LinearGradientBrush Brush_Success => Get<LinearGradientBrush>("SuccessBrush");
public static SolidColorBrush Brush_DarkSuccess => Get<SolidColorBrush>("DarkSuccessBrush");
public static SolidColorBrush Brush_Accent => Get<SolidColorBrush>("AccentBrush");
public static SolidColorBrush Brush_DarkAccent => Get<SolidColorBrush>("DarkAccentBrush");
public static SolidColorBrush Brush_DarkMask => Get<SolidColorBrush>("DarkMaskBrush");
public static SolidColorBrush Brush_DarkOpacity => Get<SolidColorBrush>("DarkOpacityBrush");
#endregion
#region Strings #region Strings

View File

@@ -0,0 +1,2 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Source="pack://application:,,,/HandyControl;component/Themes/SkinDark.xaml"/>

View File

@@ -0,0 +1,2 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>

View File

@@ -0,0 +1,2 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Source="pack://application:,,,/HandyControl;component/Themes/SkinViolet.xaml"/>

View File

@@ -197,11 +197,13 @@
<s:String x:Key="Str_VideoFormat">Video Format</s:String> <s:String x:Key="Str_VideoFormat">Video Format</s:String>
<s:String x:Key="Str_LoopPlay">Loop Play</s:String> <s:String x:Key="Str_LoopPlay">Loop Play</s:String>
<s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp]&#x0A;Whether the animation loops</s:String> <s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp/Apng]&#x0A;Whether the animation loops</s:String>
<s:String x:Key="Str_QualityParameter">Quality Parameter</s:String> <s:String x:Key="Str_QualityParameter">Quality Parameter</s:String>
<s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;Quality parameter, range 0-100, higher value means better quality</s:String> <s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;Quality parameter, range 0-100, higher value means better quality</s:String>
<s:String x:Key="Str_LosslessParam">Lossless Compression</s:String> <s:String x:Key="Str_LosslessParam">Lossless Compression</s:String>
<s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;Lossless compression, quality parameter will be ignored</s:String> <s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;Lossless compression, quality parameter will be ignored</s:String>
<s:String x:Key="Str_ApngPred">Predictor Method</s:String>
<s:String x:Key="Str_ApngPredTooltip" xml:space="preserve">[Apng]&#x0A;Pred parameter, value range 0-5, corresponding to different encoding strategies: none, sub, up, avg, paeth, and mixed.&#x0A;It affects encoding time and file size.</s:String>
<s:String x:Key="Str_CrfParameter">CRF Parameter</s:String> <s:String x:Key="Str_CrfParameter">CRF Parameter</s:String>
<s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF parameter, range 0-63, lower value means higher quality</s:String> <s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF parameter, range 0-63, lower value means higher quality</s:String>
<s:String x:Key="Str_ProfileParameter">Profile Parameter</s:String> <s:String x:Key="Str_ProfileParameter">Profile Parameter</s:String>
@@ -242,6 +244,7 @@
<s:String x:Key="Str_AppPreference">Application Options</s:String> <s:String x:Key="Str_AppPreference">Application Options</s:String>
<s:String x:Key="Str_Language">Language</s:String> <s:String x:Key="Str_Language">Language</s:String>
<s:String x:Key="Str_AppSkin">Skin</s:String>
<s:String x:Key="Str_CloseToTray">Minimize to tray when closing</s:String> <s:String x:Key="Str_CloseToTray">Minimize to tray when closing</s:String>
<s:String x:Key="Str_AutoRun">Auto Start</s:String> <s:String x:Key="Str_AutoRun">Auto Start</s:String>
<s:String x:Key="Str_AutoRunWorkspaceConfigPath">Auto-load Workspace File on Startup</s:String> <s:String x:Key="Str_AutoRunWorkspaceConfigPath">Auto-load Workspace File on Startup</s:String>

View File

@@ -197,11 +197,13 @@
<s:String x:Key="Str_VideoFormat">ビデオフォーマット</s:String> <s:String x:Key="Str_VideoFormat">ビデオフォーマット</s:String>
<s:String x:Key="Str_LoopPlay">ループ再生</s:String> <s:String x:Key="Str_LoopPlay">ループ再生</s:String>
<s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp]&#x0A;アニメーションをループ再生するかどうか</s:String> <s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp/Apng]&#x0A;アニメーションをループ再生するかどうか</s:String>
<s:String x:Key="Str_QualityParameter">品質パラメータ</s:String> <s:String x:Key="Str_QualityParameter">品質パラメータ</s:String>
<s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;品質パラメータ、範囲は0-100。値が高いほど品質が良い</s:String> <s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;品質パラメータ、範囲は0-100。値が高いほど品質が良い</s:String>
<s:String x:Key="Str_LosslessParam">無損失圧縮</s:String> <s:String x:Key="Str_LosslessParam">無損失圧縮</s:String>
<s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;無損失圧縮、品質パラメータは無視されます</s:String> <s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;無損失圧縮、品質パラメータは無視されます</s:String>
<s:String x:Key="Str_ApngPred">予測器方式</s:String>
<s:String x:Key="Str_ApngPredTooltip" xml:space="preserve">[Apng]&#x0A;Pred パラメータ。値の範囲は 05 で、それぞれ none、sub、up、avg、paeth、mixed の異なるエンコード方式に対応します。&#x0A;エンコード時間とファイルサイズに影響します。</s:String>
<s:String x:Key="Str_CrfParameter">CRF パラメータ</s:String> <s:String x:Key="Str_CrfParameter">CRF パラメータ</s:String>
<s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF パラメータ、範囲0-63。値が小さいほど品質が高い</s:String> <s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF パラメータ、範囲0-63。値が小さいほど品質が高い</s:String>
<s:String x:Key="Str_ProfileParameter">プロファイルパラメータ</s:String> <s:String x:Key="Str_ProfileParameter">プロファイルパラメータ</s:String>
@@ -242,6 +244,7 @@
<s:String x:Key="Str_AppPreference">アプリケーションプション</s:String> <s:String x:Key="Str_AppPreference">アプリケーションプション</s:String>
<s:String x:Key="Str_Language">言語</s:String> <s:String x:Key="Str_Language">言語</s:String>
<s:String x:Key="Str_AppSkin">スキン</s:String>
<s:String x:Key="Str_CloseToTray">閉じるときにトレイに最小化する</s:String> <s:String x:Key="Str_CloseToTray">閉じるときにトレイに最小化する</s:String>
<s:String x:Key="Str_AutoRun">自動起動</s:String> <s:String x:Key="Str_AutoRun">自動起動</s:String>
<s:String x:Key="Str_AutoRunWorkspaceConfigPath">起動時にワークスペースファイルを自動読み込み</s:String> <s:String x:Key="Str_AutoRunWorkspaceConfigPath">起動時にワークスペースファイルを自動読み込み</s:String>

View File

@@ -197,11 +197,13 @@
<s:String x:Key="Str_VideoFormat">视频格式</s:String> <s:String x:Key="Str_VideoFormat">视频格式</s:String>
<s:String x:Key="Str_LoopPlay">循环播放</s:String> <s:String x:Key="Str_LoopPlay">循环播放</s:String>
<s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp]&#x0A;动图是否循环播放</s:String> <s:String x:Key="Str_LoopPlayTooltip" xml:space="preserve">[Gif/Webp/Apng]&#x0A;动图是否循环播放</s:String>
<s:String x:Key="Str_QualityParameter">质量参数</s:String> <s:String x:Key="Str_QualityParameter">质量参数</s:String>
<s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;质量参数,取值范围 0-100越高质量越好</s:String> <s:String x:Key="Str_QualityParameterTooltip" xml:space="preserve">[Webp]&#x0A;质量参数,取值范围 0-100越高质量越好</s:String>
<s:String x:Key="Str_LosslessParam">无损压缩</s:String> <s:String x:Key="Str_LosslessParam">无损压缩</s:String>
<s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;无损压缩,会忽略质量参数</s:String> <s:String x:Key="Str_LosslessParamTooltip" xml:space="preserve">[Webp]&#x0A;无损压缩,会忽略质量参数</s:String>
<s:String x:Key="Str_ApngPred">预测器方法</s:String>
<s:String x:Key="Str_ApngPredTooltip" xml:space="preserve">[Apng]&#x0A;Pred 参数,取值范围 0-5分别对应 none、sub、up、avg、paeth、mixed 几种不同的编码策略,&#x0A;影响编码时间和文件大小</s:String>
<s:String x:Key="Str_CrfParameter">CRF 参数</s:String> <s:String x:Key="Str_CrfParameter">CRF 参数</s:String>
<s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF 参数,取值范围 0-63越小质量越高</s:String> <s:String x:Key="Str_CrfParameterTooltip" xml:space="preserve">[Mp4/Webm/Mkv]&#x0A;CRF 参数,取值范围 0-63越小质量越高</s:String>
<s:String x:Key="Str_ProfileParameter">Profile 参数</s:String> <s:String x:Key="Str_ProfileParameter">Profile 参数</s:String>
@@ -242,6 +244,7 @@
<s:String x:Key="Str_AppPreference">应用程序选项</s:String> <s:String x:Key="Str_AppPreference">应用程序选项</s:String>
<s:String x:Key="Str_Language">语言</s:String> <s:String x:Key="Str_Language">语言</s:String>
<s:String x:Key="Str_AppSkin">皮肤</s:String>
<s:String x:Key="Str_CloseToTray">关闭时最小化至托盘图标</s:String> <s:String x:Key="Str_CloseToTray">关闭时最小化至托盘图标</s:String>
<s:String x:Key="Str_AutoRun">开机自启</s:String> <s:String x:Key="Str_AutoRun">开机自启</s:String>
<s:String x:Key="Str_AutoRunWorkspaceConfigPath">自启动加载工作区文件</s:String> <s:String x:Key="Str_AutoRunWorkspaceConfigPath">自启动加载工作区文件</s:String>

View File

@@ -0,0 +1,83 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:o="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:utils="clr-namespace:SpineViewer.Utils"
xmlns:hc="https://handyorg.github.io/handycontrol">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
</ResourceDictionary.MergedDictionaries>
<utils:StringFormatMultiValueConverter x:Key="StrFmtCvter"/>
<utils:BackgroundToForegroundConverter x:Key="Bg2FgCvter"/>
<Style x:Key="MyGridSplitterBaseStyle" TargetType="{x:Type GridSplitter}">
<Setter Property="Background" Value="{DynamicResource SecondaryBorderBrush}"/>
<Setter Property="ShowsPreview" Value="False"/>
<Style.Triggers>
<Trigger Property="ResizeDirection" Value="Columns">
<Setter Property="Width" Value="3"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
</Trigger>
<Trigger Property="ResizeDirection" Value="Rows">
<Setter Property="Height" Value="3"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="MyToggleButtonBaseStyle" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ToggleButtonSwitch}">
<Setter Property="hc:VisualElement.HighlightBrush" Value="{DynamicResource DarkSuccessBrush}"/>
</Style>
<Style x:Key="MyListBoxBaseStyle" TargetType="{x:Type ListBox}" BasedOn="{StaticResource ListBoxBaseStyle}">
<Setter Property="SelectionMode" Value="Extended"/>
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="False"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Visible"/>
</Style>
<Style x:Key="MyListBoxItemBaseStyle" TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource ListBoxItemBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
</Style>
<Style x:Key="MyListViewBaseStyle" TargetType="{x:Type ListView}" BasedOn="{StaticResource ListViewBaseStyle}">
<Setter Property="SelectionMode" Value="Extended"/>
<Setter Property="VirtualizingPanel.IsVirtualizing" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource ListViewItemBaseStyle.Small}"/>
</Style>
<Style x:Key="MyGroupBoxBaseStyle" TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
</Style>
<Style x:Key="MyLogRichTextBoxStyle" TargetType="{x:Type RichTextBox}" BasedOn="{StaticResource RichTextBoxBaseStyle}">
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="Block.LineHeight" Value="3"/>
<Setter Property="VerticalScrollBarVisibility" Value="Visible"/>
</Style>
<Style x:Key="MyVerticalScrollViewerBaseStyle" TargetType="{x:Type ScrollViewer}" BasedOn="{StaticResource ScrollViewerNativeBaseStyle}">
<Setter Property="Padding" Value="0"/>
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Style.Triggers>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Visible">
<Setter Property="Padding" Value="0 0 5 0"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type GridSplitter}" BasedOn="{StaticResource MyGridSplitterBaseStyle}"/>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}"/>
<Style TargetType="{x:Type ListBox}" BasedOn="{StaticResource MyListBoxBaseStyle}"/>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource MyListBoxItemBaseStyle}"/>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource MyListViewBaseStyle}"/>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}"/>
</ResourceDictionary>

View File

@@ -7,7 +7,7 @@
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<BaseOutputPath>$(SolutionDir)out</BaseOutputPath> <BaseOutputPath>$(SolutionDir)out</BaseOutputPath>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<Version>0.16.3</Version> <Version>0.16.4</Version>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
</PropertyGroup> </PropertyGroup>

View File

@@ -0,0 +1,35 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace SpineViewer.Utils
{
public class BackgroundToForegroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var color = Colors.White;
if (value is SolidColorBrush brush)
{
color = brush.Color;
}
else if (value is Color c)
{
color = c;
}
if (color.A < 128)
return Brushes.Black;
// 计算亮度 (使用标准加权公式)
double brightness = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) / 255.0;
return brightness < 0.5 ? Brushes.White : Brushes.Black;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -66,8 +66,8 @@ namespace SpineViewer.Utils
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to read json file {0}, {1}", path, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to read json file {0}, {1}", path, ex.Message);
MessagePopupService.Error($"Failed to read json file {path}, {ex.ToString()}"); MessagePopupService.Error($"Failed to read json file {path}, {ex.ToString()}");
} }
} }
@@ -88,8 +88,8 @@ namespace SpineViewer.Utils
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to save json file {0}, {1}", path, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to save json file {0}, {1}", path, ex.Message);
MessagePopupService.Error($"Failed to save json file {path}, {ex.ToString()}"); MessagePopupService.Error($"Failed to save json file {path}, {ex.ToString()}");
return false; return false;
} }

View File

@@ -7,6 +7,7 @@ using Spine.Exporters;
using SpineViewer.Extensions; using SpineViewer.Extensions;
using SpineViewer.Models; using SpineViewer.Models;
using SpineViewer.Resources; using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.MainWindow; using SpineViewer.ViewModels.MainWindow;
using System; using System;
using System.Collections; using System.Collections;
@@ -74,6 +75,16 @@ namespace SpineViewer.ViewModels.Exporters
public uint MaxResolution { get => _maxResolution; set => SetProperty(ref _maxResolution, value); } public uint MaxResolution { get => _maxResolution; set => SetProperty(ref _maxResolution, value); }
protected uint _maxResolution = 2048; protected uint _maxResolution = 2048;
public RelayCommand Cmd_SelectOutputDir => _cmd_SelectOutputDir ??= new(() =>
{
if (DialogService.ShowOpenFolderDialog(out var selectedPath))
{
_outputDir = selectedPath;
OnPropertyChanged(nameof(OutputDir));
}
});
protected RelayCommand _cmd_SelectOutputDir;
/// <summary> /// <summary>
/// 使用提供的包围盒设置自动分辨率 /// 使用提供的包围盒设置自动分辨率
/// </summary> /// </summary>

View File

@@ -20,24 +20,63 @@ namespace SpineViewer.ViewModels.Exporters
{ {
public static ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormatOptions { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray(); public static ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormatOptions { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray();
public FFmpegVideoExporter.VideoFormat Format { get => _format; set => SetProperty(ref _format, value); } public FFmpegVideoExporter.VideoFormat Format
{
get => _format;
set
{
if (!SetProperty(ref _format, value))
return;
OnPropertyChanged(nameof(EnableParamLoop));
OnPropertyChanged(nameof(EnableParamQuality));
OnPropertyChanged(nameof(EnableParamLossless));
OnPropertyChanged(nameof(EnableParamApngPred));
OnPropertyChanged(nameof(EnableParamCrf));
OnPropertyChanged(nameof(EnableParamProfile));
}
}
protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4; protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4;
public bool Loop { get => _loop; set => SetProperty(ref _loop, value); } public bool Loop { get => _loop; set => SetProperty(ref _loop, value); }
protected bool _loop = true; protected bool _loop = true;
public bool EnableParamLoop =>
_format == FFmpegVideoExporter.VideoFormat.Gif ||
_format == FFmpegVideoExporter.VideoFormat.Webp ||
_format == FFmpegVideoExporter.VideoFormat.Apng;
public int Quality { get => _quality; set => SetProperty(ref _quality, Math.Clamp(value, 0, 100)); } public int Quality { get => _quality; set => SetProperty(ref _quality, Math.Clamp(value, 0, 100)); }
protected int _quality = 75; protected int _quality = 75;
public bool EnableParamQuality =>
_format == FFmpegVideoExporter.VideoFormat.Webp;
public bool Lossless { get => _lossless; set => SetProperty(ref _lossless, value); } public bool Lossless { get => _lossless; set => SetProperty(ref _lossless, value); }
protected bool _lossless = false; protected bool _lossless = false;
public bool EnableParamLossless =>
_format == FFmpegVideoExporter.VideoFormat.Webp;
public int ApngPred { get => _apngPred; set => SetProperty(ref _apngPred, Math.Clamp(value, 0, 5)); }
protected int _apngPred = 5;
public bool EnableParamApngPred =>
_format == FFmpegVideoExporter.VideoFormat.Apng;
public int Crf { get => _crf; set => SetProperty(ref _crf, Math.Clamp(value, 0, 63)); } public int Crf { get => _crf; set => SetProperty(ref _crf, Math.Clamp(value, 0, 63)); }
protected int _crf = 23; protected int _crf = 23;
public bool EnableParamCrf =>
_format == FFmpegVideoExporter.VideoFormat.Mp4 ||
_format == FFmpegVideoExporter.VideoFormat.Webm ||
_format == FFmpegVideoExporter.VideoFormat.Mkv;
public int Profile { get => _profile; set => SetProperty(ref _profile, Math.Clamp(value, -1, 5)); } public int Profile { get => _profile; set => SetProperty(ref _profile, Math.Clamp(value, -1, 5)); }
protected int _profile = 5; protected int _profile = 5;
public bool EnableParamProfile =>
_format == FFmpegVideoExporter.VideoFormat.Mov;
private string FormatSuffix => $".{_format.ToString().ToLower()}"; private string FormatSuffix => $".{_format.ToString().ToLower()}";
protected override void Export(SpineObjectModel[] models) protected override void Export(SpineObjectModel[] models)
@@ -63,6 +102,7 @@ namespace SpineViewer.ViewModels.Exporters
Loop = _loop, Loop = _loop,
Quality = _quality, Quality = _quality,
Lossless = _lossless, Lossless = _lossless,
ApngPred = _apngPred,
Crf = _crf, Crf = _crf,
Profile = _profile, Profile = _profile,
}; };

View File

@@ -20,7 +20,6 @@ using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shell; using System.Windows.Shell;
using Spine.Interfaces;
namespace SpineViewer.ViewModels.MainWindow namespace SpineViewer.ViewModels.MainWindow
{ {

View File

@@ -2,8 +2,8 @@
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Microsoft.Win32; using Microsoft.Win32;
using NLog; using NLog;
using Spine;
using Spine.Implementations; using Spine.Implementations;
using Spine.Interfaces;
using SpineViewer.Models; using SpineViewer.Models;
using SpineViewer.Natives; using SpineViewer.Natives;
using SpineViewer.Services; using SpineViewer.Services;
@@ -109,6 +109,7 @@ namespace SpineViewer.ViewModels.MainWindow
DebugClippings = DebugClippings, DebugClippings = DebugClippings,
AppLanguage = AppLanguage, AppLanguage = AppLanguage,
AppSkin = AppSkin,
RenderSelectedOnly = RenderSelectedOnly, RenderSelectedOnly = RenderSelectedOnly,
HitTestLevel = HitTestLevel, HitTestLevel = HitTestLevel,
LogHitSlots = LogHitSlots, LogHitSlots = LogHitSlots,
@@ -140,6 +141,7 @@ namespace SpineViewer.ViewModels.MainWindow
DebugClippings = value.DebugClippings; DebugClippings = value.DebugClippings;
AppLanguage = value.AppLanguage; AppLanguage = value.AppLanguage;
AppSkin = value.AppSkin;
RenderSelectedOnly = value.RenderSelectedOnly; RenderSelectedOnly = value.RenderSelectedOnly;
HitTestLevel = value.HitTestLevel; HitTestLevel = value.HitTestLevel;
LogHitSlots = value.LogHitSlots; LogHitSlots = value.LogHitSlots;
@@ -253,6 +255,8 @@ namespace SpineViewer.ViewModels.MainWindow
public static ImmutableArray<AppLanguage> AppLanguageOptions { get; } = Enum.GetValues<AppLanguage>().ToImmutableArray(); public static ImmutableArray<AppLanguage> AppLanguageOptions { get; } = Enum.GetValues<AppLanguage>().ToImmutableArray();
public static ImmutableArray<AppSkin> AppSkinOptions { get; } = Enum.GetValues<AppSkin>().ToImmutableArray();
public static ImmutableArray<HitTestLevel> HitTestLevelOptions { get; } = Enum.GetValues<HitTestLevel>().ToImmutableArray(); public static ImmutableArray<HitTestLevel> HitTestLevelOptions { get; } = Enum.GetValues<HitTestLevel>().ToImmutableArray();
public AppLanguage AppLanguage public AppLanguage AppLanguage
@@ -261,6 +265,12 @@ namespace SpineViewer.ViewModels.MainWindow
set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v); set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v);
} }
public AppSkin AppSkin
{
get => ((App)App.Current).Skin;
set => SetProperty(((App)App.Current).Skin, value, v => ((App)App.Current).Skin = v);
}
public bool RenderSelectedOnly public bool RenderSelectedOnly
{ {
get => _vmMain.SFMLRendererViewModel.RenderSelectedOnly; get => _vmMain.SFMLRendererViewModel.RenderSelectedOnly;

View File

@@ -47,11 +47,6 @@ namespace SpineViewer.ViewModels.MainWindow
/// </summary> /// </summary>
private readonly SFML.Graphics.VertexArray _selectedBackgroundVertices = new(SFML.Graphics.PrimitiveType.Quads, 4); // XXX: 暂时未使用 Dispose 释放 private readonly SFML.Graphics.VertexArray _selectedBackgroundVertices = new(SFML.Graphics.PrimitiveType.Quads, 4); // XXX: 暂时未使用 Dispose 释放
/// <summary>
/// 预览画面坐标轴颜色
/// </summary>
private static readonly SFML.Graphics.Color _axisColor = new(220, 220, 220);
/// <summary> /// <summary>
/// 坐标轴顶点缓冲区 /// 坐标轴顶点缓冲区
/// </summary> /// </summary>
@@ -178,10 +173,21 @@ namespace SpineViewer.ViewModels.MainWindow
public Color BackgroundColor public Color BackgroundColor
{ {
get => Color.FromRgb(_backgroundColor.R, _backgroundColor.G, _backgroundColor.B); get => Color.FromRgb(_backgroundColor.R, _backgroundColor.G, _backgroundColor.B);
set => SetProperty(BackgroundColor, value, v => _backgroundColor = new(value.R, value.G, value.B)); set
{
if (!SetProperty(BackgroundColor, value, v => _backgroundColor = new(value.R, value.G, value.B)))
return;
var b = (0.299 * value.R + 0.587 * value.G + 0.114 * value.B) / 255.0;
_axisColor = b < 0.5 ? SFML.Graphics.Color.White : SFML.Graphics.Color.Black;
}
} }
private SFML.Graphics.Color _backgroundColor = new(105, 105, 105); private SFML.Graphics.Color _backgroundColor = new(105, 105, 105);
/// <summary>
/// 预览画面坐标轴颜色
/// </summary>
private SFML.Graphics.Color _axisColor = SFML.Graphics.Color.White;
public string BackgroundImagePath public string BackgroundImagePath
{ {
get => _backgroundImagePath; get => _backgroundImagePath;

View File

@@ -218,8 +218,8 @@ namespace SpineViewer.ViewModels.MainWindow
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
} }
} }
} }
@@ -279,8 +279,8 @@ namespace SpineViewer.ViewModels.MainWindow
catch (Exception ex) catch (Exception ex)
{ {
error++; error++;
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
} }
} }
} }

View File

@@ -8,6 +8,7 @@
d:DataContext="{d:DesignInstance Type=viewmodels:AboutDialogViewModel}" d:DataContext="{d:DesignInstance Type=viewmodels:AboutDialogViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_Abount}" Title="{DynamicResource Str_Abount}"
Background="{DynamicResource RegionBrush}"
Height="300" Height="300"
Width="500" Width="500"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -26,25 +27,31 @@
<Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style> </Style>
</Grid.Resources> </Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 程序版本 --> <StackPanel Grid.IsSharedSizeScope="True">
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ProgremVersion}"/> <!-- 程序版本 -->
<Label Grid.Row="0" Grid.Column="1" Content="{Binding ProgramVersion}"/> <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ProgremVersion}"/>
<Label Grid.Column="1" Content="{Binding ProgramVersion}"/>
</Grid>
<!-- 项目地址 --> <!-- 项目地址 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ProjectUrl}"/> <Grid>
<Label Grid.Row="1" Grid.Column="1"> <Grid.ColumnDefinitions>
<Hyperlink NavigateUri="{Binding ProjectUrl}" Command="{Binding Cmd_OpenProjectUrl}"> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<Run Text="{Binding ProjectUrl, Mode=OneWay}"/> <ColumnDefinition Width="*"/>
</Hyperlink> </Grid.ColumnDefinitions>
</Label> <Label Content="{DynamicResource Str_ProjectUrl}"/>
<Label Grid.Column="1">
<Hyperlink NavigateUri="{Binding ProjectUrl}" Command="{Binding Cmd_OpenProjectUrl}">
<Run Text="{Binding ProjectUrl, Mode=OneWay}"/>
</Hyperlink>
</Label>
</Grid>
</StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,4 +1,6 @@
using System; using SpineViewer.Natives;
using SpineViewer.Resources;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -8,6 +10,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -22,6 +25,14 @@ namespace SpineViewer.Views
public AboutDialog() public AboutDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += AboutDialog_SourceInitialized;
}
private void AboutDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
} }
} }

View File

@@ -8,6 +8,7 @@
d:DataContext="{d:DesignInstance Type=viewmodels:DiagnosticsDialogViewModel}" d:DataContext="{d:DesignInstance Type=viewmodels:DiagnosticsDialogViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_Diagnostics}" Title="{DynamicResource Str_Diagnostics}"
Background="{DynamicResource RegionBrush}"
Height="450" Height="450"
Width="800" Width="800"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -21,7 +22,7 @@
<Button Width="120" Content="{DynamicResource Str_CopyDiagnosticsInfo}" Command="{Binding Cmd_CopyToClipboard}"/> <Button Width="120" Content="{DynamicResource Str_CopyDiagnosticsInfo}" Command="{Binding Cmd_CopyToClipboard}"/>
</Border> </Border>
<Border Grid.IsSharedSizeScope="True"> <Border>
<Border.Resources> <Border.Resources>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource LabelDefault}"> <Style TargetType="{x:Type Label}" BasedOn="{StaticResource LabelDefault}">
<Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="HorizontalAlignment" Value="Stretch"/>
@@ -31,8 +32,8 @@
<Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="30 10"> <StackPanel Grid.IsSharedSizeScope="True" Margin="30 10">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
@@ -134,7 +135,6 @@
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding HandyControlVersion, Mode=OneWay}"/> <TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding HandyControlVersion, Mode=OneWay}"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</DockPanel> </DockPanel>

View File

@@ -1,4 +1,6 @@
using System; using SpineViewer.Natives;
using SpineViewer.Resources;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -8,6 +10,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -22,6 +25,14 @@ namespace SpineViewer.Views
public DiagnosticsDialog() public DiagnosticsDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += DiagnosticsDialog_SourceInitialized;
}
private void DiagnosticsDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
} }
} }

View File

@@ -5,10 +5,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:SpineViewer.Views.ExporterDialogs" xmlns:local="clr-namespace:SpineViewer.Views.ExporterDialogs"
xmlns:utils="clr-namespace:SpineViewer.Utils"
xmlns:exporters="clr-namespace:SpineViewer.ViewModels.Exporters" xmlns:exporters="clr-namespace:SpineViewer.ViewModels.Exporters"
d:DataContext="{d:DesignInstance Type=exporters:CustomFFmpegExporterViewModel}" d:DataContext="{d:DesignInstance Type=exporters:CustomFFmpegExporterViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_CustomFFmpegExporterTitle}" Title="{DynamicResource Str_CustomFFmpegExporterTitle}"
Background="{DynamicResource RegionBrush}"
Width="450" Width="450"
Height="800" Height="800"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -39,173 +41,235 @@
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}"> <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/> <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}"> <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}">
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}"> <Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}">
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
<Setter Property="Margin" Value="0 5 0 10"/> <Setter Property="Margin" Value="0 5 0 10"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ScrollViewer Style="{StaticResource MyVerticalScrollViewerBaseStyle}">
<StackPanel Grid.IsSharedSizeScope="True"> <StackPanel Grid.IsSharedSizeScope="True">
<GroupBox Header="{DynamicResource Str_ExportBaseArgs}"> <GroupBox Header="{DynamicResource Str_ExportBaseArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 水平分辨率 --> <!-- 水平分辨率 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 垂直分辨率 --> <!-- 垂直分辨率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 是否导出单个 --> <!-- 是否导出单个 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid>
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
</Grid>
<!-- 输出文件夹 --> <!-- 输出文件夹 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <Grid>
<DockPanel Grid.Row="3" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonSelectOutputDir_Click"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <ColumnDefinition Width="*"/>
</DockPanel> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
<DockPanel Grid.Column="1">
<Button DockPanel.Dock="Right" Content="..." Command="{Binding Cmd_SelectOutputDir}"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
</DockPanel>
</Grid>
<!-- 背景颜色 --> <!-- 背景颜色 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/> <Grid>
<DockPanel Grid.Row="4" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonPickColor_Click"> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<Button.Background> <ColumnDefinition Width="*"/>
<SolidColorBrush Color="{Binding BackgroundColor}"/> </Grid.ColumnDefinitions>
</Button.Background> <Label Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/>
</Button> <DockPanel Grid.Column="1">
<TextBox x:Name="_colorTextBox" Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/> <Border DockPanel.Dock="Right">
</DockPanel> <Popup x:Name="_colorPopup" Placement="Right">
<hc:ColorPicker Confirmed="ColorPicker_Confirmed" Canceled="ColorPicker_Canceled"/>
</Popup>
</Border>
<Border DockPanel.Dock="Right" Background="White" CornerRadius="{DynamicResource DefaultCornerRadius}">
<Button Content="..."
Foreground="{Binding BackgroundColor, Converter={StaticResource Bg2FgCvter}}"
Click="ButtonPickColor_Click">
<Button.Background>
<SolidColorBrush Color="{Binding BackgroundColor}"/>
</Button.Background>
</Button>
</Border>
<TextBox Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/>
</DockPanel>
</Grid>
<!-- 四周边距 --> <!-- 四周边距 -->
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
</Grid>
<!-- 自动分辨率 --> <!-- 自动分辨率 -->
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid>
<ToggleButton Grid.Row="6" Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
</Grid>
<!-- 最大分辨率 --> <!-- 最大分辨率 -->
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution}">
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportVideoArgs}"> <GroupBox Header="{DynamicResource Str_ExportVideoArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 导出时长 --> <!-- 导出时长 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
</Grid>
<!-- 导出帧率 --> <!-- 导出帧率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_Fps}"/> <Grid>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Fps}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Fps}"/>
<TextBox Grid.Column="1" Text="{Binding Fps}"/>
</Grid>
<!-- 导出速度 --> <!-- 导出速度 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
</Grid>
<!-- 是否保留最后一帧 --> <!-- 是否保留最后一帧 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/> <Grid>
<ToggleButton Grid.Row="3" Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportOtherArgs}"> <GroupBox Header="{DynamicResource Str_ExportOtherArgs}">
<Grid> <StackPanel>
<Grid.Resources>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource LabelDefault}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource TextBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="60"/>
</Grid.RowDefinitions>
<!-- 导出格式 --> <!-- 导出格式 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_FFmpegFormat}" ToolTip="{DynamicResource Str_FFmpegFormatTooltip}"/> <Grid>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Format}" ToolTip="{DynamicResource Str_FFmpegFormatTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_FFmpegFormat}" ToolTip="{DynamicResource Str_FFmpegFormatTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Format}" ToolTip="{DynamicResource Str_FFmpegFormatTooltip}"/>
</Grid>
<!-- 编码器 --> <!-- 编码器 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_FFmpegCodec}" ToolTip="{DynamicResource Str_FFmpegCodecTooltip}"/> <Grid>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Codec}" ToolTip="{DynamicResource Str_FFmpegCodecTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_FFmpegCodec}" ToolTip="{DynamicResource Str_FFmpegCodecTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Codec}" ToolTip="{DynamicResource Str_FFmpegCodecTooltip}"/>
</Grid>
<!-- 像素格式 --> <!-- 像素格式 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_FFmpegPixelFormat}" ToolTip="{DynamicResource Str_FFmpegPixelFormatTooltip}"/> <Grid>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding PixelFormat}" ToolTip="{DynamicResource Str_FFmpegPixelFormatTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_FFmpegPixelFormat}" ToolTip="{DynamicResource Str_FFmpegPixelFormatTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding PixelFormat}" ToolTip="{DynamicResource Str_FFmpegPixelFormatTooltip}"/>
</Grid>
<!-- 比特率 --> <!-- 比特率 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_FFmpegBitrate}" ToolTip="{DynamicResource Str_FFmpegBitrateTooltip}"/> <Grid>
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Bitrate}" ToolTip="{DynamicResource Str_FFmpegBitrateTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_FFmpegBitrate}" ToolTip="{DynamicResource Str_FFmpegBitrateTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Bitrate}" ToolTip="{DynamicResource Str_FFmpegBitrateTooltip}"/>
</Grid>
<!-- 滤镜 --> <!-- 滤镜 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_FFmpegFilter}" ToolTip="{DynamicResource Str_FFmpegFilterTooltip}"/> <Grid>
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Filter}" ToolTip="{DynamicResource Str_FFmpegFilterTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_FFmpegFilter}" ToolTip="{DynamicResource Str_FFmpegFilterTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Filter}" ToolTip="{DynamicResource Str_FFmpegFilterTooltip}"/>
</Grid>
<!-- 自定义参数 --> <!-- 自定义参数 -->
<Label Grid.Row="5" Grid.Column="0" <Grid>
VerticalAlignment="Top" <Grid.ColumnDefinitions>
Content="{DynamicResource Str_FFmpegCustomArgs}" <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
ToolTip="{DynamicResource Str_FFmpegCustomArgsTooltip}"/> <ColumnDefinition Width="*"/>
<TextBox Grid.Row="5" Grid.Column="1" </Grid.ColumnDefinitions>
HorizontalContentAlignment="Left" <Label VerticalAlignment="Top"
VerticalContentAlignment="Top" Content="{DynamicResource Str_FFmpegCustomArgs}"
TextWrapping="Wrap" ToolTip="{DynamicResource Str_FFmpegCustomArgsTooltip}"/>
VerticalScrollBarVisibility="Auto" <TextBox Grid.Column="1"
Text="{Binding CustomArgs}" Height="75"
ToolTip="{DynamicResource Str_FFmpegCustomArgsTooltip}"/> HorizontalContentAlignment="Left"
</Grid> VerticalContentAlignment="Top"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto"
Text="{Binding CustomArgs}"
ToolTip="{DynamicResource Str_FFmpegCustomArgsTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public CustomFFmpegExporterDialog() public CustomFFmpegExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += CustomFFmpegExporterDialog_SourceInitialized;
}
private void CustomFFmpegExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)
@@ -42,18 +53,22 @@ namespace SpineViewer.Views.ExporterDialogs
DialogResult = false; DialogResult = false;
} }
private void ButtonSelectOutputDir_Click(object sender, RoutedEventArgs e)
{
if (DialogService.ShowOpenFolderDialog(out var selectedPath))
{
var vm = (CustomFFmpegExporterViewModel)DataContext;
vm.OutputDir = selectedPath;
}
}
private void ButtonPickColor_Click(object sender, RoutedEventArgs e) private void ButtonPickColor_Click(object sender, RoutedEventArgs e)
{ {
_colorPopup.IsOpen = !_colorPopup.IsOpen;
}
private void ColorPicker_Confirmed(object sender, HandyControl.Data.FunctionEventArgs<Color> e)
{
_colorPopup.IsOpen = false;
var color = e.Info;
var vm = (BaseExporterViewModel)DataContext;
vm.BackgroundColor = color;
}
private void ColorPicker_Canceled(object sender, EventArgs e)
{
_colorPopup.IsOpen = false;
} }
} }
} }

View File

@@ -5,10 +5,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:SpineViewer.Views.ExporterDialogs" xmlns:local="clr-namespace:SpineViewer.Views.ExporterDialogs"
xmlns:utils="clr-namespace:SpineViewer.Utils"
xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters" xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters"
d:DataContext="{d:DesignInstance Type=vmexp:FFmpegVideoExporterViewModel}" d:DataContext="{d:DesignInstance Type=vmexp:FFmpegVideoExporterViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_FFmpegVideoExporterTitle}" Title="{DynamicResource Str_FFmpegVideoExporterTitle}"
Background="{DynamicResource RegionBrush}"
Width="450" Width="450"
Height="750" Height="750"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -39,150 +41,236 @@
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}"> <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/> <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}"> <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}">
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}"> <Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}">
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
<Setter Property="Margin" Value="0 5 0 10"/> <Setter Property="Margin" Value="0 5 0 10"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer Style="{StaticResource MyVerticalScrollViewerBaseStyle}">
<StackPanel Grid.IsSharedSizeScope="True"> <StackPanel Grid.IsSharedSizeScope="True">
<GroupBox Header="{DynamicResource Str_ExportBaseArgs}"> <GroupBox Header="{DynamicResource Str_ExportBaseArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 水平分辨率 --> <!-- 水平分辨率 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 垂直分辨率 --> <!-- 垂直分辨率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 是否导出单个 --> <!-- 是否导出单个 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid>
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
</Grid>
<!-- 输出文件夹 --> <!-- 输出文件夹 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <Grid>
<DockPanel Grid.Row="3" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonSelectOutputDir_Click"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <ColumnDefinition Width="*"/>
</DockPanel> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
<DockPanel Grid.Column="1">
<Button DockPanel.Dock="Right" Content="..." Command="{Binding Cmd_SelectOutputDir}"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
</DockPanel>
</Grid>
<!-- 背景颜色 --> <!-- 背景颜色 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/> <Grid>
<DockPanel Grid.Row="4" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonPickColor_Click"> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<Button.Background> <ColumnDefinition Width="*"/>
<SolidColorBrush Color="{Binding BackgroundColor}"/> </Grid.ColumnDefinitions>
</Button.Background> <Label Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/>
</Button> <DockPanel Grid.Column="1">
<TextBox x:Name="_colorTextBox" Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/> <Border DockPanel.Dock="Right">
</DockPanel> <Popup x:Name="_colorPopup" Placement="Right">
<hc:ColorPicker Confirmed="ColorPicker_Confirmed" Canceled="ColorPicker_Canceled"/>
</Popup>
</Border>
<Border DockPanel.Dock="Right" Background="White" CornerRadius="{DynamicResource DefaultCornerRadius}">
<Button Content="..."
Foreground="{Binding BackgroundColor, Converter={StaticResource Bg2FgCvter}}"
Click="ButtonPickColor_Click">
<Button.Background>
<SolidColorBrush Color="{Binding BackgroundColor}"/>
</Button.Background>
</Button>
</Border>
<TextBox Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/>
</DockPanel>
</Grid>
<!-- 四周边距 --> <!-- 四周边距 -->
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
</Grid>
<!-- 自动分辨率 --> <!-- 自动分辨率 -->
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid>
<ToggleButton Grid.Row="6" Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
</Grid>
<!-- 最大分辨率 --> <!-- 最大分辨率 -->
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution}">
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportVideoArgs}"> <GroupBox Header="{DynamicResource Str_ExportVideoArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 导出时长 --> <!-- 导出时长 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
</Grid>
<!-- 导出帧率 --> <!-- 导出帧率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_Fps}"/> <Grid>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Fps}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Fps}"/>
<TextBox Grid.Column="1" Text="{Binding Fps}"/>
</Grid>
<!-- 导出速度 --> <!-- 导出速度 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
</Grid>
<!-- 是否保留最后一帧 --> <!-- 是否保留最后一帧 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/> <Grid>
<ToggleButton Grid.Row="3" Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportOtherArgs}"> <GroupBox Header="{DynamicResource Str_ExportOtherArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 视频格式 --> <!-- 视频格式 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_VideoFormat}"/> <Grid>
<ComboBox Grid.Row="0" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{x:Static vmexp:FFmpegVideoExporterViewModel.VideoFormatOptions}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_VideoFormat}"/>
<ComboBox Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{x:Static vmexp:FFmpegVideoExporterViewModel.VideoFormatOptions}"/>
</Grid>
<!-- 动图是否循环 --> <!-- 动图是否循环 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_LoopPlay}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/> <Grid Visibility="{Binding EnableParamLoop, Converter={StaticResource Boolean2VisibilityConverter}}">
<ToggleButton Grid.Row="1" Grid.Column="1" IsChecked="{Binding Loop}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_LoopPlay}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding Loop}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/>
</Grid>
<!-- 质量参数 --> <!-- 质量参数 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_QualityParameter}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/> <Grid Visibility="{Binding EnableParamQuality, Converter={StaticResource Boolean2VisibilityConverter}}">
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_QualityParameter}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_QualityParameterTooltip}"/>
</Grid>
<!-- 无损压缩 --> <!-- 无损压缩 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_LosslessParam}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/> <Grid Visibility="{Binding EnableParamLossless, Converter={StaticResource Boolean2VisibilityConverter}}">
<ToggleButton Grid.Row="3" Grid.Column="1" IsChecked="{Binding Lossless}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_LosslessParam}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding Lossless}" ToolTip="{DynamicResource Str_LosslessParamTooltip}"/>
</Grid>
<!-- 预测器方法 -->
<Grid Visibility="{Binding EnableParamApngPred, Converter={StaticResource Boolean2VisibilityConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ApngPred}" ToolTip="{DynamicResource Str_ApngPredTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding ApngPred}" ToolTip="{DynamicResource Str_ApngPredTooltip}"/>
</Grid>
<!-- CRF 参数 --> <!-- CRF 参数 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_CrfParameter}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/> <Grid Visibility="{Binding EnableParamCrf, Converter={StaticResource Boolean2VisibilityConverter}}">
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Crf}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_CrfParameter}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Crf}" ToolTip="{DynamicResource Str_CrfParameterTooltip}"/>
</Grid>
<!-- Profile 参数 --> <!-- Profile 参数 -->
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_ProfileParameter}" ToolTip="{DynamicResource Str_ProfileParameterTooltip}"/> <Grid Visibility="{Binding EnableParamProfile, Converter={StaticResource Boolean2VisibilityConverter}}">
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Profile}" ToolTip="{DynamicResource Str_ProfileParameterTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ProfileParameter}" ToolTip="{DynamicResource Str_ProfileParameterTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Profile}" ToolTip="{DynamicResource Str_ProfileParameterTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FFmpegVideoExporterDialog() public FFmpegVideoExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FFmpegVideoExporterDialog_SourceInitialized;
}
private void FFmpegVideoExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)
@@ -42,18 +53,22 @@ namespace SpineViewer.Views.ExporterDialogs
DialogResult = false; DialogResult = false;
} }
private void ButtonSelectOutputDir_Click(object sender, RoutedEventArgs e)
{
if (DialogService.ShowOpenFolderDialog(out var selectedPath))
{
var vm = (FFmpegVideoExporterViewModel)DataContext;
vm.OutputDir = selectedPath;
}
}
private void ButtonPickColor_Click(object sender, RoutedEventArgs e) private void ButtonPickColor_Click(object sender, RoutedEventArgs e)
{ {
_colorPopup.IsOpen = !_colorPopup.IsOpen;
}
private void ColorPicker_Confirmed(object sender, HandyControl.Data.FunctionEventArgs<Color> e)
{
_colorPopup.IsOpen = false;
var color = e.Info;
var vm = (BaseExporterViewModel)DataContext;
vm.BackgroundColor = color;
}
private void ColorPicker_Canceled(object sender, EventArgs e)
{
_colorPopup.IsOpen = false;
} }
} }
} }

View File

@@ -5,10 +5,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:SpineViewer.Views" xmlns:local="clr-namespace:SpineViewer.Views"
xmlns:utils="clr-namespace:SpineViewer.Utils"
xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters" xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters"
d:DataContext="{d:DesignInstance Type=vmexp:FrameExporterViewModel}" d:DataContext="{d:DesignInstance Type=vmexp:FrameExporterViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_FrameExporterTitle}" Title="{DynamicResource Str_FrameExporterTitle}"
Background="{DynamicResource RegionBrush}"
Width="450" Width="450"
Height="480" Height="480"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -39,99 +41,142 @@
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}"> <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/> <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}"> <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}">
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}"> <Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}">
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
<Setter Property="Margin" Value="0 5 0 10"/> <Setter Property="Margin" Value="0 5 0 10"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer Style="{StaticResource MyVerticalScrollViewerBaseStyle}">
<StackPanel Grid.IsSharedSizeScope="True"> <StackPanel Grid.IsSharedSizeScope="True">
<GroupBox Header="{DynamicResource Str_ExportBaseArgs}"> <GroupBox Header="{DynamicResource Str_ExportBaseArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 水平分辨率 --> <!-- 水平分辨率 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 垂直分辨率 --> <!-- 垂直分辨率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 是否导出单个 --> <!-- 是否导出单个 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid>
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
</Grid>
<!-- 输出文件夹 --> <!-- 输出文件夹 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <Grid>
<DockPanel Grid.Row="3" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonSelectOutputDir_Click"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <ColumnDefinition Width="*"/>
</DockPanel> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
<DockPanel Grid.Column="1">
<Button DockPanel.Dock="Right" Content="..." Command="{Binding Cmd_SelectOutputDir}"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
</DockPanel>
</Grid>
<!-- 背景颜色 --> <!-- 背景颜色 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/> <Grid>
<DockPanel Grid.Row="4" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonPickColor_Click"> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<Button.Background> <ColumnDefinition Width="*"/>
<SolidColorBrush Color="{Binding BackgroundColor}"/> </Grid.ColumnDefinitions>
</Button.Background> <Label Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/>
</Button> <DockPanel Grid.Column="1">
<TextBox x:Name="_colorTextBox" Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/> <Border DockPanel.Dock="Right">
</DockPanel> <Popup x:Name="_colorPopup" Placement="Right">
<hc:ColorPicker Confirmed="ColorPicker_Confirmed" Canceled="ColorPicker_Canceled"/>
</Popup>
</Border>
<Border DockPanel.Dock="Right" Background="White" CornerRadius="{DynamicResource DefaultCornerRadius}">
<Button Content="..."
Foreground="{Binding BackgroundColor, Converter={StaticResource Bg2FgCvter}}"
Click="ButtonPickColor_Click">
<Button.Background>
<SolidColorBrush Color="{Binding BackgroundColor}"/>
</Button.Background>
</Button>
</Border>
<TextBox Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/>
</DockPanel>
</Grid>
<!-- 四周边距 --> <!-- 四周边距 -->
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
</Grid>
<!-- 自动分辨率 --> <!-- 自动分辨率 -->
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid>
<ToggleButton Grid.Row="6" Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
</Grid>
<!-- 最大分辨率 --> <!-- 最大分辨率 -->
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution}">
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportOtherArgs}"> <GroupBox Header="{DynamicResource Str_ExportOtherArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 图像格式 --> <!-- 图像格式 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ImageFormat}"/> <Grid>
<ComboBox Grid.Row="0" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{x:Static vmexp:FrameExporterViewModel.FrameFormatOptions}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ImageFormat}"/>
<ComboBox Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{x:Static vmexp:FrameExporterViewModel.FrameFormatOptions}"/>
</Grid>
<!-- 图像质量 --> <!-- 图像质量 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ImageQuality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/> <Grid>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ImageQuality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Quality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FrameExporterDialog() public FrameExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FrameExporterDialog_SourceInitialized;
}
private void FrameExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)
@@ -42,18 +53,22 @@ namespace SpineViewer.Views.ExporterDialogs
DialogResult = false; DialogResult = false;
} }
private void ButtonSelectOutputDir_Click(object sender, RoutedEventArgs e)
{
if (DialogService.ShowOpenFolderDialog(out var selectedPath))
{
var vm = (FrameExporterViewModel)DataContext;
vm.OutputDir = selectedPath;
}
}
private void ButtonPickColor_Click(object sender, RoutedEventArgs e) private void ButtonPickColor_Click(object sender, RoutedEventArgs e)
{ {
_colorPopup.IsOpen = !_colorPopup.IsOpen;
}
private void ColorPicker_Confirmed(object sender, HandyControl.Data.FunctionEventArgs<Color> e)
{
_colorPopup.IsOpen = false;
var color = e.Info;
var vm = (BaseExporterViewModel)DataContext;
vm.BackgroundColor = color;
}
private void ColorPicker_Canceled(object sender, EventArgs e)
{
_colorPopup.IsOpen = false;
} }
} }
} }

View File

@@ -5,10 +5,12 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:SpineViewer.Views" xmlns:local="clr-namespace:SpineViewer.Views"
xmlns:utils="clr-namespace:SpineViewer.Utils"
xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters" xmlns:vmexp="clr-namespace:SpineViewer.ViewModels.Exporters"
d:DataContext="{d:DesignInstance Type=vmexp:FrameSequenceExporterViewModel}" d:DataContext="{d:DesignInstance Type=vmexp:FrameSequenceExporterViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_FrameSequenceExporterTitle}" Title="{DynamicResource Str_FrameSequenceExporterTitle}"
Background="{DynamicResource RegionBrush}"
Width="450" Width="450"
Height="550" Height="550"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -39,109 +41,162 @@
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}"> <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/> <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}"> <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}">
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}"> <Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}">
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
<Setter Property="Margin" Value="0 5 0 10"/> <Setter Property="Margin" Value="0 5 0 10"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer Style="{StaticResource MyVerticalScrollViewerBaseStyle}">
<StackPanel Grid.IsSharedSizeScope="True"> <StackPanel Grid.IsSharedSizeScope="True">
<GroupBox Header="{DynamicResource Str_ExportBaseArgs}"> <GroupBox Header="{DynamicResource Str_ExportBaseArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 水平分辨率 --> <!-- 水平分辨率 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionX}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionX, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 垂直分辨率 --> <!-- 垂直分辨率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution, Converter={StaticResource Boolean2BooleanReConverter}}">
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ResolutionY}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
<TextBox Grid.Column="1" IsReadOnly="True" Text="{Binding ResolutionY, Mode=OneWay}" ToolTip="{DynamicResource Str_ResolutionTooltip}"/>
</Grid>
<!-- 是否导出单个 --> <!-- 是否导出单个 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid>
<ToggleButton Grid.Row="2" Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ExportSingle}" ToolTip="{DynamicResource Str_ExportSingleTooltip}"/>
</Grid>
<!-- 输出文件夹 --> <!-- 输出文件夹 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <Grid>
<DockPanel Grid.Row="3" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonSelectOutputDir_Click"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/> <ColumnDefinition Width="*"/>
</DockPanel> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
<DockPanel Grid.Column="1">
<Button DockPanel.Dock="Right" Content="..." Command="{Binding Cmd_SelectOutputDir}"/>
<TextBox Text="{Binding OutputDir}" ToolTip="{DynamicResource Str_OutputDirTooltip}"/>
</DockPanel>
</Grid>
<!-- 背景颜色 --> <!-- 背景颜色 -->
<Label Grid.Row="4" Grid.Column="0" Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/> <Grid>
<DockPanel Grid.Row="4" Grid.Column="1"> <Grid.ColumnDefinitions>
<Button DockPanel.Dock="Right" Content="..." Click="ButtonPickColor_Click"> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<Button.Background> <ColumnDefinition Width="*"/>
<SolidColorBrush Color="{Binding BackgroundColor}"/> </Grid.ColumnDefinitions>
</Button.Background> <Label Content="{DynamicResource Str_BackgroundColor}" ToolTip="#AARRGGBB"/>
</Button> <DockPanel Grid.Column="1">
<TextBox x:Name="_colorTextBox" Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/> <Border DockPanel.Dock="Right">
</DockPanel> <Popup x:Name="_colorPopup" Placement="Right">
<hc:ColorPicker Confirmed="ColorPicker_Confirmed" Canceled="ColorPicker_Canceled"/>
</Popup>
</Border>
<Border DockPanel.Dock="Right" Background="White" CornerRadius="{DynamicResource DefaultCornerRadius}">
<Button Content="..."
Foreground="{Binding BackgroundColor, Converter={StaticResource Bg2FgCvter}}"
Click="ButtonPickColor_Click">
<Button.Background>
<SolidColorBrush Color="{Binding BackgroundColor}"/>
</Button.Background>
</Button>
</Border>
<TextBox Text="{Binding BackgroundColor}" ToolTip="#AARRGGBB"/>
</DockPanel>
</Grid>
<!-- 四周边距 --> <!-- 四周边距 -->
<Label Grid.Row="5" Grid.Column="0" Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Margin}" ToolTip="{DynamicResource Str_MarginTooltip}"/>
</Grid>
<!-- 自动分辨率 --> <!-- 自动分辨率 -->
<Label Grid.Row="6" Grid.Column="0" Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid>
<ToggleButton Grid.Row="6" Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AutoResolution}" ToolTip="{DynamicResource Str_AutoResolutionTooltip}"/>
</Grid>
<!-- 最大分辨率 --> <!-- 最大分辨率 -->
<Label Grid.Row="7" Grid.Column="0" Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid IsEnabled="{Binding AutoResolution}">
<TextBox Grid.Row="7" Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding MaxResolution}" ToolTip="{DynamicResource Str_MaxResolutionTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
<GroupBox Header="{DynamicResource Str_ExportVideoArgs}"> <GroupBox Header="{DynamicResource Str_ExportVideoArgs}">
<Grid> <StackPanel>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 导出时长 --> <!-- 导出时长 -->
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Duration}" ToolTip="{DynamicResource Str_ExportDurationTooltip}"/>
</Grid>
<!-- 导出帧率 --> <!-- 导出帧率 -->
<Label Grid.Row="1" Grid.Column="0" Content="{DynamicResource Str_Fps}"/> <Grid>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Fps}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Fps}"/>
<TextBox Grid.Column="1" Text="{Binding Fps}"/>
</Grid>
<!-- 导出速度 --> <!-- 导出速度 -->
<Label Grid.Row="2" Grid.Column="0" Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ExportSpeed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
<TextBox Grid.Column="1" Text="{Binding Speed}" ToolTip="{DynamicResource Str_ExportSpeedTooltip}"/>
</Grid>
<!-- 是否保留最后一帧 --> <!-- 是否保留最后一帧 -->
<Label Grid.Row="3" Grid.Column="0" Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/> <Grid>
<ToggleButton Grid.Row="3" Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/> <Grid.ColumnDefinitions>
</Grid> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_KeepLastFrame}" ToolTip="{DynamicResource Str_KeepLastFrameTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding KeepLast}" ToolTip="{DynamicResource Str_KeelLastFrameTooltip}"/>
</Grid>
</StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FrameSequenceExporterDialog() public FrameSequenceExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FrameSequenceExporterDialog_SourceInitialized;
}
private void FrameSequenceExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)
@@ -42,18 +53,22 @@ namespace SpineViewer.Views.ExporterDialogs
DialogResult = false; DialogResult = false;
} }
private void ButtonSelectOutputDir_Click(object sender, RoutedEventArgs e)
{
if (DialogService.ShowOpenFolderDialog(out var selectedPath))
{
var vm = (FrameSequenceExporterViewModel)DataContext;
vm.OutputDir = selectedPath;
}
}
private void ButtonPickColor_Click(object sender, RoutedEventArgs e) private void ButtonPickColor_Click(object sender, RoutedEventArgs e)
{ {
_colorPopup.IsOpen = !_colorPopup.IsOpen;
}
private void ColorPicker_Confirmed(object sender, HandyControl.Data.FunctionEventArgs<Color> e)
{
_colorPopup.IsOpen = false;
var color = e.Info;
var vm = (BaseExporterViewModel)DataContext;
vm.BackgroundColor = color;
}
private void ColorPicker_Canceled(object sender, EventArgs e)
{
_colorPopup.IsOpen = false;
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,12 +8,14 @@ using SpineViewer.Natives;
using SpineViewer.Resources; using SpineViewer.Resources;
using SpineViewer.Services; using SpineViewer.Services;
using SpineViewer.Utils; using SpineViewer.Utils;
using SpineViewer.ViewModels.Exporters;
using SpineViewer.ViewModels.MainWindow; using SpineViewer.ViewModels.MainWindow;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -64,11 +66,11 @@ public partial class MainWindow : Window
// XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定 // XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定
_notifyIcon.Text = _vm.Title; _notifyIcon.Text = _vm.Title;
SourceInitialized += MainWindow_SourceInitialized;
Loaded += MainWindow_Loaded; Loaded += MainWindow_Loaded;
ContentRendered += MainWindow_ContentRendered; ContentRendered += MainWindow_ContentRendered;
Closing += MainWindow_Closing; Closing += MainWindow_Closing;
Closed += MainWindow_Closed; Closed += MainWindow_Closed;
_vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging; _vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
_vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging; _vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
@@ -95,7 +97,7 @@ public partial class MainWindow : Window
rtbTarget.WordColoringRules.Add(new("[I]", "DimGray", "Empty")); rtbTarget.WordColoringRules.Add(new("[I]", "DimGray", "Empty"));
rtbTarget.WordColoringRules.Add(new("[W]", "DarkOrange", "Empty")); rtbTarget.WordColoringRules.Add(new("[W]", "DarkOrange", "Empty"));
rtbTarget.WordColoringRules.Add(new("[E]", "Red", "Empty")); rtbTarget.WordColoringRules.Add(new("[E]", "Red", "Empty"));
rtbTarget.WordColoringRules.Add(new("[F]", "DarkRed", "Empty")); rtbTarget.WordColoringRules.Add(new("[F]", "White", "DarkRed"));
LogManager.Configuration.AddTarget(rtbTarget); LogManager.Configuration.AddTarget(rtbTarget);
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Fatal, rtbTarget); LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Fatal, rtbTarget);
@@ -177,6 +179,13 @@ public partial class MainWindow : Window
#region MainWindow #region MainWindow
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{ {
var vm = _vm.SFMLRendererViewModel; var vm = _vm.SFMLRendererViewModel;
@@ -253,6 +262,28 @@ public partial class MainWindow : Window
#endregion #endregion
#region ColorPicker
private void ButtonPickColor_Click(object sender, RoutedEventArgs e)
{
_colorPopup.IsOpen = !_colorPopup.IsOpen;
}
private void ColorPicker_Confirmed(object sender, HandyControl.Data.FunctionEventArgs<Color> e)
{
_colorPopup.IsOpen = false;
var color = e.Info;
var vm = ((MainWindowViewModel)DataContext).SFMLRendererViewModel;
vm.BackgroundColor = color;
}
private void ColorPicker_Canceled(object sender, EventArgs e)
{
_colorPopup.IsOpen = false;
}
#endregion
#region ViewModel PropertyChanged #region ViewModel PropertyChanged
private void SFMLRendererViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) private void SFMLRendererViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@@ -706,14 +737,16 @@ public partial class MainWindow : Window
#endregion #endregion
private void DebugMenuItem_Click(object sender, RoutedEventArgs e) private void DebugMenuItem_Click(object sender, RoutedEventArgs e)
{ {
#if DEBUG #if DEBUG
var a = _rootGrid.ColumnDefinitions[0].Width; _logger.Debug("Debug");
var b = _rootGrid.ColumnDefinitions[1].Width; _logger.Info("Info");
var c = _rootGrid.ColumnDefinitions[2].Width; _logger.Warn("Warn");
Debug.WriteLine(a); _logger.Error("Error");
Debug.WriteLine(_rootGrid.ColumnDefinitions[0].Width.IsStar); _logger.Fatal("Fatal");
return;
#endif #endif
} }
} }

View File

@@ -10,6 +10,7 @@
d:DataContext="{d:DesignInstance Type=models:PreferenceModel}" d:DataContext="{d:DesignInstance Type=models:PreferenceModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{DynamicResource Str_Preference}" Title="{DynamicResource Str_Preference}"
Background="{DynamicResource RegionBrush}"
Height="650" Height="650"
Width="600" Width="600"
ShowInTaskbar="False" ShowInTaskbar="False"
@@ -40,24 +41,22 @@
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}"> <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboBoxBaseStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/> <Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButton}"> <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource MyToggleButtonBaseStyle}">
<Setter Property="HorizontalAlignment" Value="Right"/> <Setter Property="HorizontalAlignment" Value="Right"/>
</Style> </Style>
<Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource GroupBoxTab}"> <Style TargetType="{x:Type GroupBox}" BasedOn="{StaticResource MyGroupBoxBaseStyle}">
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="hc:TitleElement.Background" Value="Transparent"/>
<Setter Property="Margin" Value="0 5 0 10"/> <Setter Property="Margin" Value="0 5 0 10"/>
</Style> </Style>
</Border.Resources> </Border.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Grid.IsSharedSizeScope="True" Margin="0 0 0 50"> <ScrollViewer Style="{StaticResource MyVerticalScrollViewerBaseStyle}">
<StackPanel Grid.IsSharedSizeScope="True">
<GroupBox Header="{DynamicResource Str_TextureLoadPreference}"> <GroupBox Header="{DynamicResource Str_TextureLoadPreference}">
<StackPanel> <StackPanel>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/> <Label Content="{DynamicResource Str_ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding ForcePremul}" ToolTip="{DynamicResource Str_ForcePremulTooltip}"/>
@@ -66,7 +65,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ForceNearest}"/> <Label Content="{DynamicResource Str_ForceNearest}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ForceNearest}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding ForceNearest}"/>
@@ -75,7 +74,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/> <Label Content="{DynamicResource Str_ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding ForceMipmap}" ToolTip="{DynamicResource Str_ForceMipmapTooltip}"/>
@@ -88,7 +87,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_IsShown}"/> <Label Content="{DynamicResource Str_IsShown}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding IsShown}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding IsShown}"/>
@@ -97,7 +96,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_UsePma}"/> <Label Content="{DynamicResource Str_UsePma}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding UsePma}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding UsePma}"/>
@@ -106,7 +105,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugTexture}"/> <Label Content="{DynamicResource Str_DebugTexture}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugTexture}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugTexture}"/>
@@ -115,7 +114,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugBounds}"/> <Label Content="{DynamicResource Str_DebugBounds}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugBounds}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugBounds}"/>
@@ -124,7 +123,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugBones}"/> <Label Content="{DynamicResource Str_DebugBones}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugBones}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugBones}"/>
@@ -133,7 +132,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugRegions}"/> <Label Content="{DynamicResource Str_DebugRegions}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugRegions}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugRegions}"/>
@@ -142,7 +141,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugMeshHulls}"/> <Label Content="{DynamicResource Str_DebugMeshHulls}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugMeshHulls}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugMeshHulls}"/>
@@ -151,7 +150,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugMeshes}"/> <Label Content="{DynamicResource Str_DebugMeshes}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugMeshes}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugMeshes}"/>
@@ -160,7 +159,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugClippings}"/> <Label Content="{DynamicResource Str_DebugClippings}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugClippings}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugClippings}"/>
@@ -169,7 +168,7 @@
<!-- <Grid> <!-- <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugBoundingBoxes}"/> <Label Content="{DynamicResource Str_DebugBoundingBoxes}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugBoundingBoxes}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugBoundingBoxes}"/>
@@ -178,7 +177,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugPaths}"/> <Label Content="{DynamicResource Str_DebugPaths}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugPaths}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugPaths}"/>
@@ -187,7 +186,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_DebugPoints}"/> <Label Content="{DynamicResource Str_DebugPoints}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding DebugPoints}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding DebugPoints}"/>
@@ -201,7 +200,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Language}"/> <Label Content="{DynamicResource Str_Language}"/>
<ComboBox Grid.Column="1" <ComboBox Grid.Column="1"
@@ -212,7 +211,18 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_Skin}"/>
<ComboBox Grid.Column="1"
SelectedItem="{Binding AppSkin}"
ItemsSource="{x:Static vm:PreferenceViewModel.AppSkinOptions}"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_RenderSelectedOnly}"/> <Label Content="{DynamicResource Str_RenderSelectedOnly}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding RenderSelectedOnly}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding RenderSelectedOnly}"/>
@@ -221,7 +231,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_HitTestLevel}"/> <Label Content="{DynamicResource Str_HitTestLevel}"/>
<ComboBox Grid.Column="1" <ComboBox Grid.Column="1"
@@ -232,7 +242,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_LogHitSlots}" ToolTip="{DynamicResource Str_LogHitSlotsTooltip}"/> <Label Content="{DynamicResource Str_LogHitSlots}" ToolTip="{DynamicResource Str_LogHitSlotsTooltip}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding LogHitSlots}" ToolTip="{DynamicResource Str_LogHitSlotsTooltip}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding LogHitSlots}" ToolTip="{DynamicResource Str_LogHitSlotsTooltip}"/>
@@ -241,7 +251,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_WallpaperView}"/> <Label Content="{DynamicResource Str_WallpaperView}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding WallpaperView}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding WallpaperView}"/>
@@ -250,7 +260,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_CloseToTray}"/> <Label Content="{DynamicResource Str_CloseToTray}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding CloseToTray}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding CloseToTray}"/>
@@ -259,7 +269,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoRun}"/> <Label Content="{DynamicResource Str_AutoRun}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AutoRun}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding AutoRun}"/>
@@ -268,7 +278,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AutoRunWorkspaceConfigPath}" <Label Content="{DynamicResource Str_AutoRunWorkspaceConfigPath}"
ToolTip="{DynamicResource Str_AutoRunWorkspaceConfigPathTooltip}"/> ToolTip="{DynamicResource Str_AutoRunWorkspaceConfigPathTooltip}"/>
@@ -285,7 +295,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/> <ColumnDefinition Width="Auto" SharedSizeGroup="LabelCol"/>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Label Content="{DynamicResource Str_AssociateFileSuffix}"/> <Label Content="{DynamicResource Str_AssociateFileSuffix}"/>
<ToggleButton Grid.Column="1" IsChecked="{Binding AssociateFileSuffix}"/> <ToggleButton Grid.Column="1" IsChecked="{Binding AssociateFileSuffix}"/>

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views
public PreferenceDialog() public PreferenceDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += PreferenceDialog_SourceInitialized;
}
private void PreferenceDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -9,6 +9,7 @@
d:DataContext="{d:DesignInstance Type=vm:ProgressDialogViewModel}" d:DataContext="{d:DesignInstance Type=vm:ProgressDialogViewModel}"
mc:Ignorable="d" mc:Ignorable="d"
Title="{Binding Title}" Title="{Binding Title}"
Background="{DynamicResource RegionBrush}"
Width="550" Width="550"
Height="250" Height="250"
ResizeMode="NoResize" ResizeMode="NoResize"
@@ -29,7 +30,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="20 5"/> Margin="20 5"/>
<Button Grid.Row="2" <Button Grid.Row="2"
Content="{StaticResource Str_Cancel}" Content="{DynamicResource Str_Cancel}"
Command="{Binding Cmd_Cancel}" Command="{Binding Cmd_Cancel}"
Width="100" Width="100"
Margin="15"/> Margin="15"/>

View File

@@ -1,4 +1,6 @@
using SpineViewer.ViewModels; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.ViewModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -25,9 +27,17 @@ namespace SpineViewer.Views
public ProgressDialog() public ProgressDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += ProgressDialog_SourceInitialized;
Loaded += ProgressWindow_Loaded; Loaded += ProgressWindow_Loaded;
} }
private void ProgressDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
}
private void ProgressWindow_Loaded(object sender, RoutedEventArgs e) private void ProgressWindow_Loaded(object sender, RoutedEventArgs e)
{ {
var hwnd = new WindowInteropHelper(this).Handle; var hwnd = new WindowInteropHelper(this).Handle;

View File

@@ -4,7 +4,6 @@ using SFML.Graphics;
using SFML.System; using SFML.System;
using Spine; using Spine;
using Spine.Exporters; using Spine.Exporters;
using Spine.Interfaces;
namespace SpineViewerCLI namespace SpineViewerCLI
{ {