#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see .
#endregion
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using SkiaSharp;
using VocaluxeLib.Log;
namespace VocaluxeLib
{
public static class CHelper
{
private static readonly Regex _TextFileTypesRegex = new Regex("\\.txt|\\.txd", RegexOptions.IgnoreCase);
private static readonly Regex _SoundFileTypesRegex = new Regex("\\.mp3|\\.wma|\\.ogg|\\.wav", RegexOptions.IgnoreCase);
private static readonly Regex _ImageFileTypesRegex = new Regex("\\.jpg|\\.jpeg|\\.png|\\.gif", RegexOptions.IgnoreCase);
public static int CombinationCount(int n, int k)
{
if (k > n)
{
return 0;
}
if (k == 0 || k == n)
{
return 1;
}
if (k < 0 || n <= 0)
{
return 0; //is not defined
}
if (k * 2 > n)
{
k = n - k;
}
long result = n;
for (long i = 1; i <= k - 1; i++)
{
result = result * (n - i) / (i + 1);
}
return (int)result;
}
///
/// Concat strings into one string with ", " as separator.
///
public static string ListStrings(string[] str)
{
var result = string.Empty;
for (var i = 0; i < str.Length; i++)
{
result += str[i];
if (i < str.Length - 1)
{
result += ", ";
}
}
return result;
}
///
/// Places a rect within the bounds maintaining the aspectRatio and using the given aspect
///
/// Bounds to fit the rect in
/// The original aspectRatio of the rect/image/...
///
/// Crop: No empty space in bounds but has overhanging parts (same on both sides)
/// LetterBox: Fit the long side possibly leaving some space on the other (rect will be centered)
/// StretcH: Just fit the rect in the bounds (rect=bounds)
///
public static SRectF FitInBounds(SRectF bounds, float aspectRatio, EAspect aspect)
{
if (aspect == EAspect.Stretch)
{
return bounds;
}
var boundsAspectRatio = bounds.W / bounds.H;
float scaledWidth, scaledHeight;
switch (aspect)
{
case EAspect.Automatic:
case EAspect.Crop:
if (boundsAspectRatio >= aspectRatio)
{
scaledWidth = bounds.W;
scaledHeight = bounds.W / aspectRatio;
}
else
{
scaledHeight = bounds.H;
scaledWidth = bounds.H * aspectRatio;
}
break;
case EAspect.Zoom1:
if (boundsAspectRatio >= aspectRatio)
{
scaledWidth = bounds.W * 1.33f;
scaledHeight = bounds.W * 1.33f / aspectRatio;
}
else
{
scaledHeight = bounds.H / 1.33f;
scaledWidth = bounds.H / 1.33f * aspectRatio;
}
break;
case EAspect.Zoom2:
if (boundsAspectRatio >= aspectRatio)
{
scaledWidth = bounds.W * 1.17f;
scaledHeight = bounds.W * 1.17f / aspectRatio;
}
else
{
scaledHeight = bounds.H / 1.17f;
scaledWidth = bounds.H / 1.17f * aspectRatio;
}
break;
case EAspect.LetterBox:
if (boundsAspectRatio < aspectRatio)
{
scaledWidth = bounds.W;
scaledHeight = bounds.W / aspectRatio;
}
else
{
scaledHeight = bounds.H;
scaledWidth = bounds.H * aspectRatio;
}
break;
case EAspect.PillarBox:
scaledWidth = bounds.W * 0.77f;
scaledHeight = bounds.W / aspectRatio;
break;
default:
return bounds;
}
var left = (bounds.W - scaledWidth) / 2 + bounds.X;
var top = (bounds.H - scaledHeight) / 2 + bounds.Y;
return new SRectF(left, top, scaledWidth, scaledHeight, bounds.Z);
}
///
/// Returns a list with all files in the given path that match a given pattern
///
/// Path to search
/// Pattern to match (e.g. "*.jpg")
/// Search directories recursively
/// False for just file names, True for full path
/// List of file names
public static IEnumerable ListFiles(string path, string searchPattern, bool recursive = false, bool fullpath = false)
{
var files = Enumerable.Empty();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
return files;
}
if (recursive && !fullpath)
{
throw new NotSupportedException("recursive file listing with relative path names is not supported");
}
try
{
files = Directory.EnumerateFiles(dir.FullName, searchPattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
files = files.Select(fullpath ? (Func)Path.GetFullPath : Path.GetFileName);
}
catch (Exception e)
{
CLog.Error(e, "Error listing files for path " + path + " with search pattern " + searchPattern);
return Enumerable.Empty();
}
return files;
}
///
/// Returns a list with all files in the given path that match a given extension pattern
///
/// Path to search
/// File extension regex to match (e.g. "\\.jpg|\\.png")
/// Search directories recursively
/// False for just file names, True for full path
/// List of file names
public static IEnumerable ListFilesForExtPattern(string path, Regex extPattern, bool recursive = false, bool fullpath = false)
{
var files = Enumerable.Empty();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
return files;
}
if (recursive && !fullpath)
{
throw new NotSupportedException("recursive file listing with relative path names is not supported");
}
try
{
files = Directory.EnumerateFiles(path, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
.Where(file => extPattern.IsMatch(Path.GetExtension(file)));
files = files.Select(fullpath ? (Func)Path.GetFullPath : Path.GetFileName);
}
catch (Exception e)
{
CLog.Error(e, "Error listing files for path " + path + " with regex " + extPattern.ToString());
return Enumerable.Empty();
}
return files;
}
///
/// Returns a list with all text files in the given path
///
/// Path to search for
/// Search directories recursively
/// False for just file names, True for full path
/// List of text file names
public static IEnumerable ListTextFiles(string path, bool recursive = false, bool fullpath = false)
{
return ListFilesForExtPattern(path, _TextFileTypesRegex, recursive, fullpath);
}
///
/// Returns a list with all image files in the given path
///
/// Path to search for
/// Search directories recursively
/// False for just file names, True for full path
/// List of image file names
public static IEnumerable ListImageFiles(string path, bool recursive = false, bool fullpath = false)
{
return ListFilesForExtPattern(path, _ImageFileTypesRegex, recursive, fullpath);
}
///
/// Returns a list with all image files in the given path
///
/// Path to search for
/// Search directories recursively
/// False for just file names, True for full path
/// List of image file names
public static IEnumerable ListSoundFiles(string path, bool recursive = false, bool fullpath = false)
{
return ListFilesForExtPattern(path, _SoundFileTypesRegex, recursive, fullpath);
}
public static bool TryParse(string value, out T result, bool ignoreCase = false)
where T : struct
{
result = default(T);
try
{
result = (T)Enum.Parse(typeof(T), value, ignoreCase);
return true;
}
catch { }
return false;
}
public static bool TryParse(string value, out float result)
{
value = value.Replace(',', '.');
return Single.TryParse(value, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, NumberFormatInfo.InvariantInfo, out result);
}
public static bool IsInBounds(SRectF bounds, SMouseEvent mouseEvent)
{
return IsInBounds(bounds, mouseEvent.X, mouseEvent.Y);
}
public static bool IsInBounds(SRectF bounds, int x, int y)
{
return ((float)x).IsInRange(bounds.X, bounds.X + bounds.W) && ((float)y).IsInRange(bounds.Y, bounds.Y + bounds.H);
}
///
/// Returns a filename that is unique in that path
///
/// Path in which the file should be stored
/// filename (including extension)
/// Whether the fullpath or only the filename should be returned
///
public static string GetUniqueFileName(string path, string filename, bool withPath = true)
{
var ext = Path.GetExtension(filename);
filename = Path.GetFileNameWithoutExtension(filename) ?? "1";
if (File.Exists(Path.Combine(path, filename + ext)))
{
var i = 1;
while (File.Exists(Path.Combine(path, filename + "_" + i + ext)))
{
i++;
}
filename += "_" + i;
}
if (withPath)
{
filename = Path.Combine(path, filename);
}
return filename + ext;
}
public static int Sum(int n)
{
return (n * n + n) / 2;
}
///
/// Loads a bitmap from a file logging errors
///
/// Full path to image file
/// Bitmap or null on error
public static SKBitmap LoadBitmap(string filePath)
{
if (!File.Exists(filePath))
{
CLog.Error("Can't find File: " + filePath);
return null;
}
SKBitmap bmp;
try
{
bmp = SKBitmap.Decode(filePath);
}
catch (Exception)
{
bmp = null;
}
if (bmp == null)
{
CLog.Error("Error loading bitmap: " + filePath);
return null;
}
return bmp;
}
public static float EaseOutBack(float t)
{
const float overshoot = 1.70158f;
t -= 1f;
return t * t * ((overshoot + 1f) * t + overshoot) + 1f;
}
public static float EaseOutCubic(float t)
{
t = 1f - t;
return 1f - t * t * t;
}
}
}