Merge branch 'feature/load-next-file' into 'release/0.1.1.008-alpha'

Feature/load next file

See merge request SympatheticFire/video-preview!1
This commit is contained in:
Ray 2021-11-03 11:24:16 +00:00
commit 9c6e359153
10 changed files with 498 additions and 165 deletions

View File

@ -60,6 +60,15 @@ namespace VideoPreview {
}
}
/// <summary>
/// Looks up a localized string similar to Video Preview.
/// </summary>
internal static string AppName {
get {
return ResourceManager.GetString("AppName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AppName" xml:space="preserve">
<value>Video Preview</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="loading_block" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\loading-block.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>

35
MainForm.Designer.cs generated
View File

@ -42,6 +42,7 @@ namespace VideoPreview
this.button2 = new RyzStudio.Windows.ThemedForms.TButton();
this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
this.button3 = new RyzStudio.Windows.ThemedForms.TButton();
this.button4 = new RyzStudio.Windows.ThemedForms.TButton();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
@ -164,7 +165,7 @@ namespace VideoPreview
this.textBox1.Name = "textBox1";
this.textBox1.NormalImage = ((System.Drawing.Image)(resources.GetObject("textBox1.NormalImage")));
this.textBox1.Padding = new System.Windows.Forms.Padding(10, 10, 9, 9);
this.textBox1.Size = new System.Drawing.Size(294, 35);
this.textBox1.Size = new System.Drawing.Size(286, 35);
this.textBox1.SubmitButton = null;
this.textBox1.TabIndex = 16;
this.textBox1.UseSystemPasswordChar = false;
@ -173,14 +174,14 @@ namespace VideoPreview
//
this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button2.BackColor = System.Drawing.Color.Transparent;
this.button2.DefaultImage = null;
this.button2.DownImage = null;
this.button2.DefaultImage = global::VideoPreview.UIResource.cog2;
this.button2.DownImage = global::VideoPreview.UIResource.cog;
this.button2.IsSelected = false;
this.button2.LabelText = "";
this.button2.Location = new System.Drawing.Point(12, 705);
this.button2.Margin = new System.Windows.Forms.Padding(10);
this.button2.Name = "button2";
this.button2.OverImage = null;
this.button2.OverImage = global::VideoPreview.UIResource.cog;
this.button2.Padding = new System.Windows.Forms.Padding(4, 4, 3, 3);
this.button2.Size = new System.Drawing.Size(37, 37);
this.button2.TabIndex = 17;
@ -191,20 +192,38 @@ namespace VideoPreview
//
this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.button3.BackColor = System.Drawing.Color.Transparent;
this.button3.DefaultImage = null;
this.button3.DownImage = null;
this.button3.DefaultImage = global::VideoPreview.UIResource.refresh2;
this.button3.DownImage = global::VideoPreview.UIResource.refresh;
this.button3.IsSelected = false;
this.button3.LabelText = "";
this.button3.Location = new System.Drawing.Point(410, 9);
this.button3.Margin = new System.Windows.Forms.Padding(10);
this.button3.Name = "button3";
this.button3.OverImage = null;
this.button3.OverImage = global::VideoPreview.UIResource.refresh;
this.button3.Padding = new System.Windows.Forms.Padding(4, 4, 3, 3);
this.button3.Size = new System.Drawing.Size(35, 35);
this.button3.TabIndex = 23;
this.toolTip1.SetToolTip(this.button3, "Refresh");
this.button3.MouseClick += new System.Windows.Forms.MouseEventHandler(this.button3_MouseClick);
//
// button4
//
this.button4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.button4.BackColor = System.Drawing.Color.Transparent;
this.button4.DefaultImage = global::VideoPreview.UIResource.arrow_right2;
this.button4.DownImage = global::VideoPreview.UIResource.arrow_right;
this.button4.IsSelected = false;
this.button4.LabelText = "";
this.button4.Location = new System.Drawing.Point(53, 705);
this.button4.Margin = new System.Windows.Forms.Padding(10);
this.button4.Name = "button4";
this.button4.OverImage = global::VideoPreview.UIResource.arrow_right;
this.button4.Padding = new System.Windows.Forms.Padding(4, 4, 3, 3);
this.button4.Size = new System.Drawing.Size(37, 37);
this.button4.TabIndex = 24;
this.toolTip1.SetToolTip(this.button4, "Next");
this.button4.MouseClick += new System.Windows.Forms.MouseEventHandler(this.button4_MouseClick);
//
// label4
//
this.label4.AutoSize = true;
@ -262,6 +281,7 @@ namespace VideoPreview
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(250)))), ((int)(((byte)(250)))), ((int)(((byte)(250)))));
this.ClientSize = new System.Drawing.Size(464, 761);
this.Controls.Add(this.button4);
this.Controls.Add(this.button3);
this.Controls.Add(this.label6);
this.Controls.Add(this.label7);
@ -305,6 +325,7 @@ namespace VideoPreview
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Label label7;
private RyzStudio.Windows.ThemedForms.TButton button3;
private RyzStudio.Windows.ThemedForms.TButton button4;
}
}

View File

@ -1,10 +1,13 @@
using MediaToolkit;
using MediaToolkit.Model;
using MediaToolkit.Options;
using RyzStudio.IO;
using RyzStudio.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -30,11 +33,6 @@ namespace VideoPreview
textBox1.InnerTextBox.ReadOnly = true;
textBox1.InnerTextBox.BackColor = Color.White;
textBox1.InnerTextBox.TextChanged += textBox1_TextChanged;
button2.DefaultImage = UIResource.cog2;
button2.DownImage = button2.OverImage = UIResource.cog;
button3.DefaultImage = UIResource.refresh2;
button3.DownImage = button3.OverImage = UIResource.refresh;
}
protected override void OnFormClosing(FormClosingEventArgs e)
@ -64,118 +62,6 @@ namespace VideoPreview
}
//private void button1_Click(object sender, EventArgs e)
//{
// //string searchPattern = "*.avi|*.mp4|*.ogm|*.mkv";
// //string[] parts = searchPattern.Split(',', ';', '|');
// //var inputFile = new MediaFile { Filename = videoFilename };
// ////var outputFile = new MediaFile { Filename = @"N:\#\invincible.2021.s01e02.here.goes.nothing.720p.webrip.hevc.x265.mkv.jpg" };
// //using (var engine = new Engine())
// //{
// // engine.GetMetadata(inputFile);
// // // Saves the frame located on the 15th second of the video.
// // var options = new ConversionOptions { Seek = TimeSpan.FromSeconds(150) };
// // engine.GetThumbnail(inputFile, outputFile, options);
// //}
// //int i = 0;
// //FFmpegLoader.FFmpegPath = @"L:\repos\WinFormsApp1\bin\Debug\net5.0-windows";
// //MediaFile file = MediaFile.Open(@"N:\#\invincible.2021.s01e03.who.you.calling.ugly.720p.webrip.hevc.x265.mkv");
// //FFMediaToolkit.Graphics.ImageData img;
// //if (file.Video.TryGetNextFrame(out img))
// //{
// // //img..ToBitmap()
// //}
// //while (file.Video.TryGetNextFrame(out var imageData))
// //{
// // imageData.ToBitmap().Save($@"C:\images\frame_{i++}.png");
// // // See the #Usage details for example .ToBitmap() implementation
// // // The .Save() method may be different depending on your graphics library
// //}
// //MessageBox.Show("!");
//}
//private async void button2_Click(object sender, EventArgs e)
//{
// //await Task.Run(() =>
// //{
// // if (string.IsNullOrWhiteSpace(textBox1.Text)) return;
// // if (!Directory.Exists(textBox1.Text)) return;
// // ThreadControl.Clear(richTextBox1);
// // //string[] extensionFilters = new string[] { ".avi", ".mp4", ".ogm", ".mkv" };
// // ThreadControl.SetText(textBox1, @"C:\Windows");
// // List<string> fileList = RyzStudio.IO.SmarterFileSystem.GetFiles(textBox1.Text, "*.avi|*.mp4|*.ogm|*.mkv", SearchOption.AllDirectories);
// // //string[] fileList = Directory.GetFiles(textBox1.Text, "*.avi|*.mp4|*.ogm|*.mkv", SearchOption.TopDirectoryOnly);
// // foreach (string item in fileList)
// // {
// // ThreadControl.AddLine(richTextBox1, item);
// // //if (IsMatchExtension(item, extensionFilters))
// // //{
// // // ThreadControl.AddLine(richTextBox1, item);
// // //}
// // }
// // MessageBox.Show("!");
// //});
//}
//private bool IsMatchExtension(string filename, string[] extensionFilters)
//{
// string ext = Path.GetExtension(filename)?.ToLower();
// foreach (var item in extensionFilters)
// {
// if (ext.Equals(item))
// {
// return true;
// }
// }
// return false;
//}
//private string[] Split(string lines)
//{
// string[] rs = new string[0];
// foreach (string item in lines.Split(',', ';', '|'))
// {
// if (string.IsNullOrWhiteSpace(item))
// {
// continue;
// }
// Array.Resize(ref rs, (rs.Length + 1));
// rs[(rs.Length - 1)] = item?.Trim();
// }
// return rs;
//}
private void Form1_DragOver(object sender, DragEventArgs e)
{
e.Effect = (e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None);
@ -206,11 +92,24 @@ namespace VideoPreview
public AppSession CurrentSession { get; set; } = new AppSession();
private void button1_MouseClick(object sender, MouseEventArgs e)
/// <summary>
/// Refresh
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button3_MouseClick(object sender, MouseEventArgs e)
{
this.Close();
if (this.IsBusy) return;
if (string.IsNullOrWhiteSpace(textBox1.Text)) return;
await ReadVideoFile(textBox1.Text);
}
/// <summary>
/// Options
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_MouseClick(object sender, MouseEventArgs e)
{
if (this.IsBusy)
@ -227,9 +126,33 @@ namespace VideoPreview
}
}
private async void button3_MouseClick(object sender, MouseEventArgs e)
/// <summary>
/// Next file
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button4_MouseClick(object sender, MouseEventArgs e)
{
await ReadVideoFile(textBox1.Text);
await Task.Run(() =>
{
if (this.IsBusy) return;
if (string.IsNullOrWhiteSpace(textBox1.Text)) return;
string path = AccessibleDirectory.GetNextFile(textBox1.Text, "*.avi;*.mkv;*.mp4;*.ogm;*.mov;*.mpg;*.mpeg");
if (string.IsNullOrWhiteSpace(path)) return;
textBox1.Text = path;
});
}
/// <summary>
/// Close
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_MouseClick(object sender, MouseEventArgs e)
{
this.Close();
}
@ -246,6 +169,7 @@ namespace VideoPreview
videoFilename = null;
videoDuration = TimeSpan.FromSeconds(0);
ThreadControl.SetText(this, AppResource.AppName);
textBox1.Text = string.Empty;
ThreadControl.SetText(label5, "-");
ThreadControl.SetText(label7, "-");
@ -291,37 +215,6 @@ namespace VideoPreview
}
}
//protected string GetTempFolder()
//{
// string path = Path.Combine(Application.StartupPath, "tmp");
// if (Directory.Exists(path))
// {
// return path;
// }
// try
// {
// Directory.CreateDirectory(path);
// }
// catch
// {
// // do nothing
// }
// if (Directory.Exists(path))
// {
// return path;
// }
// path = Path.GetTempPath();
// if (Directory.Exists(path))
// {
// return path;
// }
// return null;
//}
protected decimal ParseFrameSizeRatio(string videoSize)
{
if (string.IsNullOrWhiteSpace(videoSize))
@ -361,10 +254,7 @@ namespace VideoPreview
{
await Task.Run(() =>
{
if (this.IsBusy)
{
return;
}
if (this.IsBusy) return;
this.IsBusy = true;
@ -375,7 +265,7 @@ namespace VideoPreview
Filename = filename
};
using (Engine engine = new Engine())
using (Engine engine = new Engine(Path.GetDirectoryName(Application.ExecutablePath) + @"\ffmpeg.exe"))
{
try
{
@ -393,6 +283,8 @@ namespace VideoPreview
videoFilename = filename;
videoDuration = inputFile.Metadata.Duration;
ThreadControl.SetText(this, Path.GetFileName(filename) + " - " + AppResource.AppName);
textBox1.Text = videoFilename;
ThreadControl.SetText(label5, inputFile.Metadata.VideoData.Format ?? string.Empty);
ThreadControl.SetText(label7, (inputFile.Metadata.VideoData.FrameSize ?? string.Empty) + " @ " + inputFile.Metadata.VideoData.Fps.ToString() + "FPS");

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

View File

@ -0,0 +1,381 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace RyzStudio.IO
{
public class AccessibleDirectory
{
public static List<string> GetFiles(string path, string pattern, bool searchTopOnly)
{
List<string> fileList = new List<string>();
List<string> directoryList = new List<string>();
if (string.IsNullOrWhiteSpace(pattern)) pattern = "*";
directoryList.Add(path);
while (true)
{
if (directoryList.Count <= 0)
{
break;
}
string directory = directoryList.First();
directoryList.RemoveAt(0);
if (IsDirectoryAccessible(directory))
{
IEnumerable<string> searchDirList = new List<string>();
try
{
searchDirList = Directory.EnumerateDirectories(directory, "*", SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
continue;
}
if (!searchTopOnly)
{
foreach (string item in searchDirList)
{
if (!IsDirectoryAccessible(item))
{
continue;
}
directoryList.Add(item);
}
}
foreach (string item in Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly))
{
if (!MatchFileSearchPattern(pattern, Path.GetFileName(item)))
{
continue;
}
if (!IsFileAccessible(item))
{
continue;
}
fileList.Add(item);
}
}
}
return fileList;
}
public static IEnumerable<string> EnumerateFiles(string path, string pattern, bool searchTopOnly)
{
List<string> directoryList = new List<string>();
if (string.IsNullOrWhiteSpace(pattern)) pattern = "*";
directoryList.Add(path);
while (true)
{
if (directoryList.Count <= 0)
{
yield break;
}
string directory = directoryList.First();
directoryList.RemoveAt(0);
if (IsDirectoryAccessible(directory))
{
IEnumerable<string> searchDirList = new List<string>();
try
{
searchDirList = Directory.EnumerateDirectories(directory, "*", SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
continue;
}
if (!searchTopOnly)
{
foreach (string item in searchDirList)
{
if (!IsDirectoryAccessible(item))
{
continue;
}
directoryList.Add(item);
}
}
foreach (string item in Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly))
{
if (!MatchFileSearchPattern(pattern, Path.GetFileName(item)))
{
continue;
}
if (!IsFileAccessible(item))
{
continue;
}
yield return item;
}
}
}
}
public static void GetFiles(string path, string pattern, bool searchTopOnly, Func<string, ulong, int, bool> callback)
{
List<string> directoryList = new List<string>();
ulong searchCount = 0;
if (string.IsNullOrWhiteSpace(pattern)) pattern = "*";
directoryList.Add(path);
searchCount++;
while (true)
{
if (directoryList.Count <= 0)
{
break;
}
string directory = directoryList.First();
directoryList.RemoveAt(0);
callback(null, searchCount, directoryList.Count);
if (IsDirectoryAccessible(directory))
{
IEnumerable<string> searchDirList = new List<string>();
try
{
searchDirList = Directory.EnumerateDirectories(directory, "*", SearchOption.TopDirectoryOnly);
}
catch (Exception)
{
continue;
}
if (!searchTopOnly)
{
foreach (string item in searchDirList)
{
if (!IsDirectoryAccessible(item))
{
continue;
}
directoryList.Add(item);
searchCount++;
callback(null, searchCount, directoryList.Count);
}
}
foreach (string item in Directory.EnumerateFiles(directory, "*", SearchOption.TopDirectoryOnly))
{
if (!MatchFileSearchPattern(pattern, Path.GetFileName(item)))
{
continue;
}
if (!IsFileAccessible(item))
{
continue;
}
callback(item, searchCount, directoryList.Count);
}
}
}
}
public static string GetNextFile(string filepath, string pattern)
{
if (string.IsNullOrWhiteSpace(filepath)) return null;
string path = Path.GetDirectoryName(filepath);
if (string.IsNullOrWhiteSpace(path)) return null;
string filename = Path.GetFileName(filepath);
if (string.IsNullOrWhiteSpace(filename)) return null;
List<string> fileList = AccessibleDirectory.GetFiles(path, pattern, true);
if (fileList == null) return null;
if (fileList.Count <= 0) return null;
if (fileList.Count(x => (Path.GetFileName(x).Equals(filename))) < 0) return null;
int pos = fileList.FindIndex(x => Path.GetFileName(x).Equals(filename));
if (pos < 0) return null;
if (pos >= (fileList.Count - 1)) return null;
return fileList[(pos + 1)];
}
public static bool IsAccessible(string path)
{
if (string.IsNullOrWhiteSpace(path)) return false;
if (File.Exists(path)) return IsFileAccessible(path);
if (Directory.Exists(path)) return IsDirectoryAccessible(path);
return false;
}
public static bool IsFileAccessible(string filename)
{
if (string.IsNullOrWhiteSpace(filename)) return false;
if (!File.Exists(filename)) return false;
try
{
FileInfo fi = new FileInfo(filename);
fi.GetAccessControl();
}
catch
{
return false;
}
return true;
}
public static bool IsDirectoryAccessible(string path)
{
if (string.IsNullOrWhiteSpace(path)) return false;
if (!Directory.Exists(path)) return false;
try
{
DirectoryInfo di = new DirectoryInfo(path);
di.GetAccessControl();
}
catch
{
return false;
}
return true;
}
public static bool MatchFileSearchPattern(string pattern, string subject)
{
if (string.IsNullOrWhiteSpace(pattern))
{
return false;
}
Func<string, string, bool> matchPattern = (pattern, subject) =>
{
string[] parts = pattern.Split('*');
if (parts.Length <= 1)
{
return subject.Equals(pattern, StringComparison.CurrentCultureIgnoreCase);
}
int pos = 0;
for (int i = 0; i < parts.Length; i++)
{
if (i <= 0)
{
// first
pos = subject.IndexOf(parts[i], pos, StringComparison.CurrentCultureIgnoreCase);
if (pos != 0)
{
return false;
}
}
else if (i >= (parts.Length - 1))
{
// last
if (!subject.EndsWith(parts[i], StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
}
else
{
pos = subject.IndexOf(parts[i], pos, StringComparison.CurrentCultureIgnoreCase);
if (pos < 0)
{
return false;
}
pos += parts[i].Length;
}
}
return true;
};
Func<string, string, bool> matchAllPattern = (pattern, subject) =>
{
int wildcardCount = pattern.Count(x => x.Equals('*'));
if (wildcardCount <= 0)
{
return subject.Equals(pattern, StringComparison.CurrentCultureIgnoreCase);
}
else if (wildcardCount == 1)
{
string newWildcardPattern = pattern.Replace("*", "");
if (pattern.StartsWith("*"))
{
return subject.EndsWith(newWildcardPattern, StringComparison.CurrentCultureIgnoreCase);
}
else if (pattern.EndsWith("*"))
{
return subject.StartsWith(newWildcardPattern, StringComparison.CurrentCultureIgnoreCase);
}
else
{
return matchPattern(pattern, subject);
}
}
else
{
return matchPattern(pattern, subject);
}
};
if (pattern.Contains(';'))
{
string[] parts = pattern.Split(';');
for (int i=0; i<parts.Length; i++)
{
if (string.IsNullOrWhiteSpace(parts[i]))
{
continue;
}
if (matchAllPattern(parts[i].Trim(), subject))
{
return true;
}
}
return false;
}
else
{
return matchAllPattern(pattern, subject);
}
}
}
}

20
UIResource.Designer.cs generated
View File

@ -60,6 +60,26 @@ namespace VideoPreview {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap arrow_right {
get {
object obj = ResourceManager.GetObject("arrow_right", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap arrow_right2 {
get {
object obj = ResourceManager.GetObject("arrow_right2", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -118,6 +118,12 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="arrow_right" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\UI\arrow_right.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="arrow_right2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\UI\arrow_right2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="cog" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\UI\cog.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

View File

@ -11,7 +11,7 @@
<Copyright>Ray Lam</Copyright>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<NoWin32Manifest>true</NoWin32Manifest>
<Version>0.1.0.097</Version>
<Version>0.1.1.008</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@ -61,6 +61,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="RyzStudio\IO\AccessibleDirectory.cs" />
<Compile Include="RyzStudio\Windows\ThemedForms\PickerBox\TPickerBox.cs" />
<Compile Include="RyzStudio\Windows\ThemedForms\PickerBox\TPickerBox.designer.cs" />
<Compile Include="RyzStudio\Windows\ThemedForms\PickerBox\TNumericPickerBox.cs">