├── .editorconfig ├── .gitattributes ├── .gitignore ├── Analytics ├── Error.cs ├── ErrorEvent.cs ├── Errors.cs ├── Exception.Generic.cs ├── ILog.cs ├── Log.cs ├── LogEntry.cs ├── Message.cs ├── Result.cs ├── ResultLevel.cs ├── ResultTypes.cs ├── Success.Generic.cs ├── Success.cs ├── Warning.cs ├── Warnings.cs └── XLog.cs ├── Base ├── Base.cs ├── Checkable.cs ├── Disposable.cs ├── Lockable.cs ├── Namable.cs ├── NamableCategory.cs ├── Savable.cs └── Updatable.cs ├── Collections ├── CollectionChangedEvent.cs ├── Generic │ ├── ImmutableCollection.Base.cs │ ├── ImmutableCollection.cs │ ├── ObjectDictionary.cs │ └── StringDictionary.cs ├── ICollectionChanged.cs ├── IGroup.cs ├── ILimit.cs ├── Limit.cs ├── ObjectModel │ ├── ChangeCollection.cs │ ├── GroupCollection.cs │ ├── GroupItem.cs │ ├── IItemChanged.cs │ ├── NamableCollection.cs │ ├── ObservableCollection.cs │ └── ObservableHistory.cs └── Serialization │ └── IWriter.cs ├── Conversion └── IConvert.cs ├── Core.csproj ├── Core.csproj.user ├── Core ├── Accessor.cs ├── Array.cs ├── Attribute.cs ├── Attributes.cs ├── Copy.cs ├── Current.cs ├── Handle.cs ├── Instances.cs ├── Resource.cs ├── Try.cs └── While.cs ├── Data ├── DataFolders.cs ├── SortDescription.cs └── SortDirection.cs ├── Enum ├── Appearance.cs ├── CardinalDirection.cs ├── Exclusivity.cs ├── LeftRight.cs ├── Quality.cs ├── RelativeDirection.cs ├── TopBottom.cs └── Types.cs ├── Input ├── BooleanEvent.cs ├── CanceledEvent.cs ├── ChangedEvent.cs ├── CheckedEvent.cs ├── DefaultEvent.cs ├── LockedEvent.cs ├── Modified.cs ├── SelectedEvent.cs └── WeakEvent.cs ├── Interface ├── IChange.cs ├── ICheck.cs ├── IContainer.cs ├── IDescription.cs ├── IEntry.cs ├── IFind.cs ├── IGeneric.cs ├── ILock.cs ├── IModify.cs ├── IName.cs ├── IParse.cs ├── IPropertyChanged.cs ├── IRange.Generic.cs ├── IRange.cs ├── IReset.cs ├── IRotate.cs ├── ISelect.cs ├── ISubscribe.cs └── IUnsubscribe.cs ├── LICENSE ├── Linq ├── Array.Generic.cs ├── Array.cs ├── Assembly.cs ├── Boolean.cs ├── Bullets.cs ├── Convert.cs ├── DateTime.cs ├── Double.cs ├── Enum.cs ├── Expression.cs ├── ICollection.cs ├── ICommand.cs ├── IDictionary.cs ├── IEnumerable.Generic.cs ├── IEnumerable.cs ├── IList.Generic.cs ├── IList.cs ├── IMatrix.cs ├── IPropertyChanged.cs ├── IRange.Generic.cs ├── IVector.cs ├── Int32.cs ├── MemberInfo.cs ├── MethodInfo.cs ├── Object.Generic.cs ├── Object.cs ├── Stack.cs ├── Stream.cs ├── String.cs ├── TimeSpan.cs ├── TimeZone.cs ├── Type.cs ├── Unit.cs └── Version.cs ├── Local ├── CultureAttribute.cs └── Language.cs ├── Logo.png ├── Models ├── ViewModel.Generic.cs └── ViewModel.cs ├── Numerics ├── Angle.cs ├── AngleUnit.cs ├── Axis2D.cs ├── Axis3D.cs ├── Dimensions.cs ├── Formula.cs ├── Formulas.cs ├── IMatrix.cs ├── IPoint2.cs ├── ISize.cs ├── IVector.cs ├── Line.cs ├── LineCollection.cs ├── M.cs ├── MLine.cs ├── MRange.cs ├── MRegion.cs ├── MSize.cs ├── MVector2.cs ├── MVector3.cs ├── MVector4.cs ├── MathParser.cs ├── Matrix.Generic.cs ├── Matrix.cs ├── Number.cs ├── NumberFormat.cs ├── NumberOperation.cs ├── NumberStyle.cs ├── NumberType.cs ├── One.cs ├── Operators.cs ├── Point2.Generic.cs ├── Point2.cs ├── Quadrants.cs ├── Random.cs ├── Range.cs ├── RangeFormat.cs ├── Shapes2.cs ├── Shapes3.cs ├── SizeProperty.cs ├── UDouble.cs ├── USingle.cs ├── Unit.cs ├── Vector.Byte.cs ├── Vector.Generic.cs ├── Vector.cs └── VectorType.cs ├── Properties └── AssemblyInfo.cs ├── Reflection ├── AssemblyContext.cs ├── AssemblyInfo.cs ├── AssemblySource.cs ├── AssemblyType.cs ├── ICloneHandler.cs └── MemberView.cs ├── Serialization ├── BinarySerializer.cs ├── ISerialize.cs ├── SerializationType.cs └── XmlCallbackSerializer.cs ├── Storage ├── Extensions.cs ├── FileAttribute.cs ├── FileSize.cs ├── FileSizeFormat.cs └── StoragePath.cs ├── Text ├── Bullets.cs ├── Characters.cs ├── Encoding.cs ├── Expressions.cs ├── StringType.cs ├── SymmetricAlgorithm.cs └── Wrapping.cs ├── Threading ├── IMethod.cs ├── Method.cs ├── Operation.cs ├── OperationType.cs ├── Queue.cs ├── TaskManagement.cs └── TaskQueue.cs ├── Time ├── BaseTimer.cs ├── Meridiem.cs ├── Relativity.cs ├── TickEvent.cs ├── TimeZone.cs └── Timer.cs ├── project.json ├── project.lock.json └── readme.md /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # IDE0022: Use block body for methods 4 | csharp_style_expression_bodied_methods =true:silent 5 | csharp_style_expression_bodied_local_functions=true:silent 6 | csharp_style_expression_bodied_lambdas=true:silent 7 | csharp_style_expression_bodied_operators=true:silent 8 | csharp_style_expression_bodied_constructors=true:silent 9 | 10 | # IDE0011: Add braces 11 | csharp_prefer_braces = false 12 | 13 | # IDE0036: Order modifiers 14 | dotnet_diagnostic.IDE0036.severity = none 15 | 16 | [*.{cs,vb}] 17 | dotnet_style_predefined_type_for_locals_parameters_members=true:silent 18 | 19 | # IDE0040: Add accessibility modifiers 20 | dotnet_style_require_accessibility_modifiers = never 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Other 18 | .vs 19 | bin 20 | obj 21 | 22 | # Windows shortcuts 23 | *.lnk 24 | 25 | # ========================= 26 | # Operating System Files 27 | # ========================= 28 | 29 | # OSX 30 | # ========================= 31 | 32 | .DS_Store 33 | .AppleDouble 34 | .LSOverride 35 | 36 | # Thumbnails 37 | ._* 38 | 39 | # Files that might appear in the root of a volume 40 | .DocumentRevisions-V100 41 | .fseventsd 42 | .Spotlight-V100 43 | .TemporaryItems 44 | .Trashes 45 | .VolumeIcon.icns 46 | 47 | # Directories potentially created on remote AFP share 48 | .AppleDB 49 | .AppleDesktop 50 | Network Trash Folder 51 | Temporary Items 52 | .apdisk 53 | -------------------------------------------------------------------------------- /Analytics/Error.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Xml.Serialization; 4 | 5 | namespace Imagin.Core.Analytics; 6 | 7 | /// Represents an unsuccessful that encapsulates an . 8 | [Serializable] 9 | public class Error : Result 10 | { 11 | [XmlAttribute] 12 | public string FullName { get => Get(""); set => Set(value); } 13 | 14 | [XmlElement] 15 | public Error Inner { get => Get(); set => Set(value); } 16 | 17 | [XmlAttribute] 18 | public string Name { get => Get(""); set => Set(value); } 19 | 20 | [XmlElement] 21 | public string StackTrace { get => Get(""); set => Set(value); } 22 | 23 | [XmlIgnore] 24 | public override ResultTypes Type => ResultTypes.Error; 25 | 26 | public Error() : this(new Exception()) { } 27 | 28 | public Error(object message) : this(new Exception($"{message}")) { } 29 | 30 | public Error(Exception exception) : base(exception.Message) 31 | { 32 | exception = exception ?? new Exception(); 33 | 34 | Inner 35 | = exception.InnerException != null 36 | ? new Error(exception.InnerException) 37 | : null; 38 | 39 | Text 40 | = exception.Message; 41 | Name 42 | = exception.GetType().GetAttribute()?.Name ?? exception.GetType().Name; 43 | FullName 44 | = exception.GetType().FullName; 45 | StackTrace 46 | = exception.StackTrace; 47 | } 48 | } -------------------------------------------------------------------------------- /Analytics/ErrorEvent.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | public delegate void ErrorEventHandler(object sender, ErrorEventArgs e); 6 | 7 | public class ErrorEventArgs : EventArgs 8 | { 9 | public ErrorEventArgs(Error input) : base(input) { } 10 | } -------------------------------------------------------------------------------- /Analytics/Errors.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | public class ChildNotFoundException : Exception 6 | { 7 | public ChildNotFoundException() : base($"'{typeof(Parent).FullName}' must have logical or visual child of type '{typeof(Child).FullName}'.") { } 8 | } 9 | 10 | public class DeserializationFailedException : Exception 11 | { 12 | public DeserializationFailedException(Type type, Exception inner = null) : base($"'{type.FullName}' failed to deserialize.", inner) { } 13 | } 14 | 15 | public class ExternalChangeException : Exception 16 | { 17 | public ExternalChangeException(string propertyName) : base($"External changes to '{typeof(Object).FullName}.{propertyName}' are not allowed.") { } 18 | } 19 | 20 | public class FileNotSupported : Exception 21 | { 22 | public FileNotSupported(string filePath) : base($"The file '{filePath}' is not supported.") { } 23 | } 24 | 25 | public class InvalidAncestor : Exception 26 | { 27 | public InvalidAncestor() : base($"'{typeof(Target).FullName}' must be an ancestor.") { } 28 | } 29 | 30 | public class InvalidFileException : Exception 31 | { 32 | public InvalidFileException(string filePath) : base($"The file '{filePath}' is invalid or corrupt.") { } 33 | } 34 | 35 | public class ParentNotFoundException : Exception 36 | { 37 | public ParentNotFoundException() : base($"'{typeof(Child).FullName}' must have logical or visual parent of type '{typeof(Parent).FullName}'.") { } 38 | } 39 | 40 | public class NotCloneableException : Exception 41 | { 42 | public NotCloneableException() : base($"'{typeof(T).FullName}' is not cloneable.") { } 43 | } 44 | 45 | public class SerializationFailedException : Exception 46 | { 47 | public SerializationFailedException(Type type, Exception inner = null) : base($"'{type.FullName}' failed to serialize.", inner) { } 48 | } 49 | 50 | [Name("Wrong password")] 51 | public class WrongPasswordException : Exception 52 | { 53 | public WrongPasswordException() : base("The password entered is incorrect.") { } 54 | } -------------------------------------------------------------------------------- /Analytics/Exception.Generic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | public class Exception : Exception 6 | { 7 | public readonly T Value; 8 | 9 | public Exception() : base() { } 10 | 11 | public Exception(T value, string message = "", Exception innerException = null) : base(message, innerException) 12 | { 13 | Value = value; 14 | } 15 | } -------------------------------------------------------------------------------- /Analytics/ILog.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Analytics; 2 | 3 | public interface ILog 4 | { 5 | int Count { get; } 6 | 7 | bool Enabled { get; } 8 | 9 | void Clear(); 10 | 11 | void Add(LogEntry input); 12 | 13 | Result Save(); 14 | } -------------------------------------------------------------------------------- /Analytics/Log.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | public static class Log 6 | { 7 | public static void Write(Result result, ResultLevel level = ResultLevel.Normal, [CallerMemberName] string member = "", [CallerLineNumber] int line = 0) 8 | => Current.Get()?.Write(result, level, member, line); 9 | } -------------------------------------------------------------------------------- /Analytics/LogEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Imagin.Core.Analytics; 5 | 6 | [Serializable] 7 | [XmlType("Entry")] 8 | public class LogEntry : Base 9 | { 10 | [XmlAttribute] 11 | public DateTime Added { get => Get(DateTime.Now); set => Set(value); } 12 | 13 | [XmlAttribute] 14 | public ResultLevel Level { get => Get(ResultLevel.Normal); set => Set(value); } 15 | 16 | [XmlAttribute] 17 | public int Line { get => Get(0); set => Set(value); } 18 | 19 | [XmlAttribute] 20 | public string Member { get => Get(""); set => Set(value); } 21 | 22 | [XmlElement] 23 | public Result Result { get => Get(); set => Set(value); } 24 | 25 | [XmlAttribute] 26 | public string Sender { get => Get(""); set => Set(value); } 27 | 28 | public LogEntry() : base() { } 29 | 30 | internal LogEntry(ResultLevel level, string sender, Result result, string member, int line) 31 | { 32 | Level 33 | = level; 34 | Sender 35 | = sender; 36 | Result 37 | = result; 38 | Member 39 | = member; 40 | Line 41 | = line; 42 | } 43 | } -------------------------------------------------------------------------------- /Analytics/Message.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Imagin.Core.Analytics; 5 | 6 | [Serializable] 7 | public class Message : Result 8 | { 9 | [XmlIgnore] 10 | public override ResultTypes Type => ResultTypes.Message; 11 | 12 | public Message() : base() { } 13 | 14 | public Message(object text = null) : base(text) { } 15 | } -------------------------------------------------------------------------------- /Analytics/Result.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Xml.Serialization; 4 | 5 | namespace Imagin.Core.Analytics; 6 | 7 | /// 8 | /// Represents a result. 9 | /// 10 | [Serializable] 11 | public abstract class Result : Base 12 | { 13 | [XmlElement] 14 | public string Text { get => Get(""); set => Set(value); } 15 | 16 | [XmlIgnore] 17 | public abstract ResultTypes Type { get; } 18 | 19 | protected Result() : base() { } 20 | 21 | public Result(object text) : this() => Text = $"{text}"; 22 | 23 | public static implicit operator bool(Result a) => a?.Type == ResultTypes.Success; 24 | 25 | public static implicit operator Result(Exception e) => new Error(e); 26 | 27 | public static implicit operator Result(string i) => new Message(i); 28 | 29 | public static implicit operator Result(bool i) => i ? (Result)new Success() : new Error(); 30 | 31 | public void If(bool i, Action action) => ((bool)this).If(i, action); 32 | 33 | public override string ToString() => Text; 34 | } -------------------------------------------------------------------------------- /Analytics/ResultLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | [Flags, Serializable] 6 | public enum ResultLevel 7 | { 8 | [Hide] 9 | None = 0, 10 | [Color("3A3")] 11 | Low = 1, 12 | [Color("FC0")] 13 | Normal = 2, 14 | [Color("C30")] 15 | High = 4, 16 | [Hide] 17 | All = Low | Normal | High 18 | } -------------------------------------------------------------------------------- /Analytics/ResultTypes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | [Flags] 6 | [Serializable] 7 | public enum ResultTypes 8 | { 9 | [Hide] 10 | None = 0, 11 | Error = 1, 12 | Message = 2, 13 | Success = 4, 14 | Warning = 8, 15 | [Hide] 16 | All = Error | Message | Success | Warning 17 | } -------------------------------------------------------------------------------- /Analytics/Success.Generic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Imagin.Core.Analytics; 5 | 6 | [Serializable] 7 | public class Success : Result 8 | { 9 | [XmlIgnore] 10 | public readonly T Data; 11 | 12 | [XmlIgnore] 13 | public override ResultTypes Type => ResultTypes.Success; 14 | 15 | protected Success() : base() { } 16 | 17 | public Success(T data, object text = null) : base(text) 18 | { 19 | Data = data; 20 | } 21 | } -------------------------------------------------------------------------------- /Analytics/Success.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | [Serializable] 6 | public class Success : Success 7 | { 8 | public Success() : base() { } 9 | 10 | public Success(object data, object text = null) : base(data, text) { } 11 | 12 | public Success(string text) : this(null, text) { } 13 | } -------------------------------------------------------------------------------- /Analytics/Warning.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Xml.Serialization; 3 | 4 | namespace Imagin.Core.Analytics; 5 | 6 | [Serializable] 7 | public class Warning : Result 8 | { 9 | [XmlIgnore] 10 | public override ResultTypes Type => ResultTypes.Warning; 11 | 12 | protected Warning() : base() { } 13 | 14 | public Warning(object message = null) : base(message) { } 15 | } -------------------------------------------------------------------------------- /Analytics/Warnings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | public class MemberMissingAttributeWarning : Warning where T : Attribute 6 | { 7 | public MemberMissingAttributeWarning(string name, Type type) : base($"Member '{name}' of type '{type.FullName}' is missing '{typeof(T).FullName}' attribute.") { } 8 | } 9 | 10 | public class NotSerializableWarning : Warning 11 | { 12 | public NotSerializableWarning(object input) : base($"'{input.GetType().FullName}' is not marked as serializable.") { } 13 | } -------------------------------------------------------------------------------- /Analytics/XLog.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Imagin.Core.Analytics; 4 | 5 | public static class XLog 6 | { 7 | public static void Write(this ILog input, Result result, ResultLevel level = ResultLevel.Normal, [CallerMemberName] string member = "", [CallerLineNumber] int line = 0) 8 | { 9 | if (input.Enabled) 10 | input.Add(new LogEntry(level, typeof(T).Name, result, member, line)); 11 | } 12 | } -------------------------------------------------------------------------------- /Base/Base.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.Generic; 2 | using Imagin.Core.Conversion; 3 | using Imagin.Core.Input; 4 | using System; 5 | using System.ComponentModel; 6 | using System.Linq.Expressions; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.Serialization; 9 | using System.Xml.Serialization; 10 | 11 | namespace Imagin.Core; 12 | 13 | /// Specifies an that implements . 14 | [Serializable] 15 | public abstract class Base : object, IModify, IPropertyChanged 16 | { 17 | [NonSerialized] 18 | ObjectDictionary NonSerializedProperties = new(); 19 | ObjectDictionary IPropertyChanged.NonSerializedProperties => NonSerializedProperties; 20 | 21 | readonly ObjectDictionary SerializedProperties = new(); 22 | ObjectDictionary IPropertyChanged.SerializedProperties => SerializedProperties; 23 | 24 | /// 25 | 26 | [Hide] 27 | [field: NonSerialized] 28 | public event ModifiedEventHandler Modified; 29 | event ModifiedEventHandler IModify.Modified { add => Modified += value; remove => Modified -= value; } 30 | 31 | [Hide] 32 | [field: NonSerialized] 33 | public event PropertyChangedEventHandler PropertyChanged; 34 | 35 | /// 36 | 37 | [Hide, XmlIgnore] 38 | public virtual bool IsModified { get => Get(false, false); set => Set(value, false); } 39 | 40 | /// 41 | 42 | [OnDeserialized] 43 | void OnDeserialized(StreamingContext input) => NonSerializedProperties ??= new(); 44 | 45 | /// 46 | 47 | [Hide] 48 | public virtual void OnModified(ModifiedEventArgs e) 49 | { 50 | IsModified = true; 51 | Modified?.Invoke(this, e); 52 | } 53 | 54 | [Hide] 55 | public virtual void OnPropertyChanged(PropertyEventArgs e) => PropertyChanged?.Invoke(this, new(e.PropertyName)); 56 | 57 | [Hide] 58 | public virtual void OnPropertyChanging(PropertyChangingEventArgs e) { } 59 | 60 | [Hide] 61 | public virtual void OnPropertyGet(GetPropertyEventArgs e) { } 62 | 63 | /// 64 | 65 | public T Get(T defaultValue = default, bool serialize = true, [CallerMemberName] string propertyName = "") 66 | => XPropertyChanged.Get(this, defaultValue, serialize, propertyName); 67 | 68 | /// 69 | 70 | public A GetFrom(A defaultValue, IConvert convert, bool serialize = true, [CallerMemberName] string propertyName = "") 71 | => XPropertyChanged.GetFrom(this, defaultValue, convert, serialize, propertyName); 72 | 73 | public T GetFromString(T defaultValue, bool serializable = true, [CallerMemberName] string propertyName = "") where T : Enum 74 | => XPropertyChanged.GetFromString(this, defaultValue, serializable, propertyName); 75 | 76 | /// 77 | 78 | public bool Set(T newValue, bool serialize = true, bool handle = false, [CallerMemberName] string propertyName = "") 79 | => XPropertyChanged.Set(this, newValue, serialize, handle, propertyName); 80 | 81 | public bool Set(Expression> propertyName, T value, bool serialize = true, bool handle = false) 82 | => XPropertyChanged.Set(this, propertyName, value, serialize, handle); 83 | 84 | /// 85 | 86 | public bool SetFrom(A newValue, IConvert convert, bool serialize = true, bool handle = false, [CallerMemberName] string propertyName = "") 87 | => XPropertyChanged.SetFrom(this, newValue, convert, serialize, handle, propertyName); 88 | 89 | public bool SetFromString(T newValue, bool serialize = true, bool handle = false, [CallerMemberName] string propertyName = "") where T : Enum 90 | => XPropertyChanged.SetFromString(this, newValue, serialize, handle, propertyName); 91 | 92 | [Hide] 93 | public void Update(Expression> propertyName) 94 | => XPropertyChanged.Update(this, propertyName); 95 | } 96 | 97 | /// 98 | [Serializable] 99 | public abstract class Base : Base 100 | { 101 | public virtual T Value { get => Get(default); set => Set(value); } 102 | 103 | public Base() : base() { } 104 | 105 | public Base(T value) : this() => Value = value; 106 | } -------------------------------------------------------------------------------- /Base/Checkable.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | using Imagin.Core.Linq; 3 | using System; 4 | 5 | namespace Imagin.Core; 6 | 7 | #region Checkable 8 | 9 | /// Specifies an that implements . 10 | public class Checkable : Base, ICheck 11 | { 12 | public event EventHandler Checked; 13 | 14 | public event CheckedEventHandler StateChanged; 15 | 16 | public event EventHandler Unchecked; 17 | 18 | public virtual bool? IsChecked { get => Get(null); set => Set(value); } 19 | 20 | public Checkable() : base() { } 21 | 22 | public Checkable(bool isChecked = false) => IsChecked = isChecked; 23 | 24 | public override void OnPropertyChanged(PropertyEventArgs e) 25 | { 26 | base.OnPropertyChanged(e); 27 | if (e.PropertyName == nameof(IsChecked)) 28 | IsChecked?.If(true, OnChecked, OnUnchecked); 29 | } 30 | 31 | public override string ToString() => IsChecked?.ToString() ?? "Indeterminate"; 32 | 33 | protected virtual void OnChecked() 34 | { 35 | Checked?.Invoke(this, new EventArgs()); 36 | OnStateChanged(true); 37 | } 38 | 39 | protected virtual void OnIndeterminate() => OnStateChanged(null); 40 | 41 | protected virtual void OnStateChanged(bool? State) => StateChanged?.Invoke(this, new CheckedEventArgs(State)); 42 | 43 | protected virtual void OnUnchecked() 44 | { 45 | Unchecked?.Invoke(this, new EventArgs()); 46 | OnStateChanged(false); 47 | } 48 | } 49 | 50 | #endregion 51 | 52 | #region Checkable 53 | 54 | /// 55 | /// Specifies an that implements (inherits ). 56 | public class BaseCheckable : Checkable 57 | { 58 | public T Value { get => Get(); set => Set(value); } 59 | 60 | public override string ToString() => Value.ToString(); 61 | 62 | public BaseCheckable() : this(false) { } 63 | 64 | public BaseCheckable(T value, bool isChecked = false) : this(isChecked) => Value = value; 65 | 66 | public BaseCheckable(bool isChecked = false) : base(isChecked) { } 67 | } 68 | 69 | #endregion -------------------------------------------------------------------------------- /Base/Disposable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | /// Specifies an that implements . 6 | [Serializable] 7 | public abstract class Disposable : Base, IDisposable 8 | { 9 | bool disposed = false; 10 | 11 | public Disposable() : base() { } 12 | 13 | ~Disposable() 14 | { 15 | Dispose(false); 16 | } 17 | 18 | void Dispose(bool disposing) 19 | { 20 | if (disposed) 21 | return; 22 | 23 | if (disposing) 24 | OnManagedDisposed(); 25 | 26 | OnUnmanagedDisposed(); 27 | disposed = true; 28 | } 29 | 30 | /// 31 | /// Occurs when managed resources need disposed. 32 | /// 33 | protected virtual void OnManagedDisposed() { } 34 | 35 | /// 36 | /// Occurs when unmanaged resources need disposed. 37 | /// 38 | protected virtual void OnUnmanagedDisposed() { } 39 | 40 | public void Dispose() 41 | { 42 | Dispose(true); 43 | GC.SuppressFinalize(this); 44 | } 45 | } -------------------------------------------------------------------------------- /Base/Lockable.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | using System; 3 | 4 | namespace Imagin.Core; 5 | 6 | /// Specifies an that locks and unlocks. 7 | [Serializable] 8 | public class Lockable : Base, ILock 9 | { 10 | [field: NonSerialized] 11 | public event LockedEventHandler Locked; 12 | 13 | [Hide, NonSerializable] 14 | public virtual bool IsLocked { get => Get(false); set => Set(value); } 15 | 16 | public Lockable() : base() { } 17 | 18 | public override void OnPropertyChanged(PropertyEventArgs e) 19 | { 20 | base.OnPropertyChanged(e); 21 | if (e.PropertyName == nameof(IsLocked)) 22 | OnLocked(IsLocked); 23 | } 24 | 25 | [Hide] 26 | public virtual void OnLocked(bool isLocked) => Locked?.Invoke(this, new LockedEventArgs(isLocked)); 27 | } -------------------------------------------------------------------------------- /Base/Namable.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.ObjectModel; 2 | using Imagin.Core.Input; 3 | using System; 4 | 5 | namespace Imagin.Core; 6 | 7 | #region Namable 8 | 9 | /// Specifies an that implements . 10 | [Serializable] 11 | public class Namable : Base, IName 12 | { 13 | public const string DefaultName = "Untitled"; 14 | 15 | [field: NonSerialized] 16 | public event EventHandler> NameChanged; 17 | 18 | [Assign(nameof(DefaultNames)), Pin(Pin.AboveOrLeft), Horizontal, Index(0), Modify] 19 | public virtual string Name { get => Get(""); set => Set(value); } 20 | 21 | [Hide] 22 | public object DefaultNames => new ObservableCollection() { DefaultName }; 23 | 24 | public Namable() : base() { } 25 | 26 | public Namable(string name) : base() => Name = name; 27 | 28 | protected virtual void OnNameChanged(string Value) => NameChanged?.Invoke(this, new EventArgs(Value)); 29 | 30 | protected virtual string OnPreviewNameChanged(string OldValue, string NewValue) => NewValue; 31 | 32 | public override void OnPropertyChanging(PropertyChangingEventArgs e) 33 | { 34 | base.OnPropertyChanging(e); 35 | if (e.PropertyName == nameof(Name)) 36 | e.NewValue = OnPreviewNameChanged((string)e.OldValue, (string)e.NewValue); 37 | } 38 | 39 | public override void OnPropertyChanged(PropertyEventArgs e) 40 | { 41 | base.OnPropertyChanged(e); 42 | if (e.PropertyName == nameof(Name)) 43 | OnNameChanged(Name); 44 | } 45 | 46 | public override string ToString() => Name; 47 | } 48 | 49 | #endregion 50 | 51 | #region Namable 52 | 53 | /// 54 | /// with a generic value. 55 | [Serializable] 56 | public class Namable : Namable 57 | { 58 | public virtual T Value { get => Get(); set => Set(value); } 59 | 60 | public Namable() : base() { } 61 | 62 | public Namable(string name) : base(name) { } 63 | 64 | public Namable(string name, T value) : this(name) => Value = value; 65 | } 66 | 67 | #endregion -------------------------------------------------------------------------------- /Base/NamableCategory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | /// 6 | [Serializable] 7 | public class NamableCategory : Namable 8 | { 9 | public string Category { get => Get(""); set => Set(value); } 10 | 11 | public NamableCategory() : base() { } 12 | 13 | public NamableCategory(string name, string category = default) : base(name) => Category = category; 14 | 15 | public NamableCategory(string name, string category, T value) : base(name, value) => Category = category; 16 | } -------------------------------------------------------------------------------- /Base/Savable.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | using Imagin.Core.Collections.Serialization; 3 | using Imagin.Core.Linq; 4 | using Imagin.Core.Serialization; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Runtime.Serialization; 9 | 10 | namespace Imagin.Core; 11 | 12 | [Serializable] 13 | public abstract class Savable : Base 14 | { 15 | [field: NonSerialized] 16 | public event EventHandler Saved; 17 | 18 | [field: NonSerialized] 19 | public event EventHandler Saving; 20 | 21 | /// 22 | 23 | protected abstract string FileExtension { get; } 24 | 25 | protected abstract string FileName { get; } 26 | 27 | protected string FilePath => $@"{FolderPath}\{FileName}.{FileExtension}"; 28 | 29 | protected abstract string FolderPath { get; } 30 | 31 | /// 32 | 33 | protected virtual void OnSaving() => Saving?.Invoke(this, EventArgs.Empty); 34 | 35 | protected virtual void OnSaved() => Saved?.Invoke(this, EventArgs.Empty); 36 | 37 | /// 38 | 39 | public Result Save() 40 | { 41 | OnSaving(); 42 | var result = BinarySerializer.Serialize(FilePath, this); 43 | OnSaved(); 44 | 45 | return result; 46 | } 47 | 48 | public virtual Result Load(out T output) where T : Savable 49 | { 50 | var result = BinarySerializer.Deserialize(FilePath, out object options); 51 | output = (T)options ?? (T)this; 52 | return result; 53 | } 54 | } 55 | 56 | [Serializable] 57 | public abstract class DataSavable : Savable 58 | { 59 | public DataSavable() : base() => OnLoaded(); 60 | 61 | [OnDeserialized] 62 | void OnDeserialized(StreamingContext input) => OnLoaded(); 63 | 64 | protected virtual IEnumerable GetData() => default; 65 | 66 | protected virtual void OnLoaded() 67 | { 68 | GetData().If(i => i.Count() > 0, i => i.ForEach(j => j.Load())); 69 | } 70 | 71 | protected override void OnSaved() 72 | { 73 | base.OnSaved(); 74 | GetData().If(i => i.Count() > 0, i => i.ForEach(j => j.Save())); 75 | } 76 | } -------------------------------------------------------------------------------- /Base/Updatable.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Timers; 4 | 5 | namespace Imagin.Core; 6 | 7 | /// 8 | [Serializable] 9 | public class Updatable : Disposable 10 | { 11 | /// 12 | /// The default interval to use. 13 | /// 14 | public readonly static TimeSpan DefaultInterval = 1.Seconds(); 15 | 16 | /// 17 | /// Occurs when the timer elapses. 18 | /// 19 | public event ElapsedEventHandler Updated; 20 | 21 | [field: NonSerialized] 22 | protected Timer timer; 23 | 24 | /// 25 | /// Initializes an instance of . 26 | /// 27 | public Updatable() : this(DefaultInterval) { } 28 | 29 | /// 30 | /// Initializes an instance of . 31 | /// 32 | public Updatable(TimeSpan interval, bool enabled = false) : base() => Reset(interval, enabled); 33 | 34 | void OnElapsed(object sender, ElapsedEventArgs e) => OnUpdate(e); 35 | 36 | void Unload() 37 | { 38 | if (timer != null) 39 | { 40 | timer.Enabled = false; 41 | timer.Elapsed -= OnElapsed; 42 | timer.Dispose(); 43 | } 44 | } 45 | 46 | protected void Reset(TimeSpan interval, bool enabled = false) 47 | { 48 | Unload(); 49 | timer = new Timer(); 50 | timer.Elapsed += OnElapsed; 51 | timer.Interval = interval.TotalMilliseconds; 52 | timer.Enabled = enabled; 53 | } 54 | 55 | /// 56 | /// Occurs when the timer elapses. 57 | /// 58 | /// 59 | protected virtual void OnUpdate(ElapsedEventArgs e) => Updated?.Invoke(this, e); 60 | 61 | /// 62 | protected override void OnUnmanagedDisposed() 63 | { 64 | base.OnUnmanagedDisposed(); 65 | Unload(); 66 | } 67 | } -------------------------------------------------------------------------------- /Collections/CollectionChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | 3 | namespace Imagin.Core.Collections; 4 | 5 | public delegate void CollectionChangedEventHandler(object sender, EventArgs e); -------------------------------------------------------------------------------- /Collections/Generic/ImmutableCollection.Base.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core.Collections.Generic; 6 | 7 | public abstract class BaseImmutableCollection : ICollection, ICollection, IEnumerable, IEnumerable 8 | { 9 | /// 10 | /// Throws . 11 | /// 12 | bool ICollection.IsSynchronized => throw new NotImplementedException(); 13 | 14 | /// 15 | /// Throws . 16 | /// 17 | object ICollection.SyncRoot => throw new NotImplementedException(); 18 | 19 | public abstract int Count { get; } 20 | 21 | public bool IsReadOnly => true; 22 | 23 | void ICollection.CopyTo(Array Array, int Index) => CopyTo((T[])Array, Index); 24 | 25 | public abstract bool Contains(T item); 26 | 27 | public abstract void CopyTo(T[] Array, int ArrayIndex); 28 | 29 | public abstract IEnumerator GetEnumerator(); 30 | 31 | /// 32 | /// Throws . 33 | /// 34 | public void Add(T Item) => throw new NotSupportedException(); 35 | 36 | /// 37 | /// Throws . 38 | /// 39 | public void Clear() => throw (new NotSupportedException()); 40 | 41 | /// 42 | /// Throws . 43 | /// 44 | public bool Remove(T Item) => throw (new NotSupportedException()); 45 | 46 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 47 | } 48 | -------------------------------------------------------------------------------- /Collections/Generic/ImmutableCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Imagin.Core.Collections.Generic; 5 | 6 | public class ImmutableCollection : BaseImmutableCollection 7 | { 8 | /// 9 | /// The collection wrapped by this class to restrict access. 10 | /// 11 | readonly IList source; 12 | 13 | public override int Count => source.Count; 14 | 15 | public ImmutableCollection(IEnumerable source) => this.source = new List(source); 16 | 17 | public ImmutableCollection() : this(Enumerable.Empty()) { } 18 | 19 | public override bool Contains(T Item) => source.Contains(Item); 20 | 21 | public override void CopyTo(T[] Array, int ArrayIndex) => source.CopyTo(Array, ArrayIndex); 22 | 23 | public override IEnumerator GetEnumerator() => source.GetEnumerator(); 24 | } -------------------------------------------------------------------------------- /Collections/Generic/ObjectDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Imagin.Core.Collections.Generic; 6 | 7 | [Serializable] 8 | public class ObjectDictionary : Dictionary 9 | { 10 | protected ObjectDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } 11 | 12 | public ObjectDictionary() : base() { } 13 | } -------------------------------------------------------------------------------- /Collections/Generic/StringDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | 5 | namespace Imagin.Core.Collections.Generic; 6 | 7 | [Serializable] 8 | public class StringDictionary : Dictionary 9 | { 10 | protected StringDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } 11 | 12 | public StringDictionary() : base() { } 13 | } -------------------------------------------------------------------------------- /Collections/ICollectionChanged.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | using System.Collections; 3 | using System.Collections.Specialized; 4 | 5 | namespace Imagin.Core.Collections; 6 | 7 | /// 8 | /// Represents a non-generic collection of objects that can be individually accessed by index, and notifies listeners of dynamic changes, such as when an item is added and removed or the whole list is cleared. 9 | /// 10 | /// 11 | /// Implements and . 12 | /// 13 | public interface ICollectionChanged : IList, INotifyCollectionChanged 14 | { 15 | event CancelEventHandler Removing; 16 | } -------------------------------------------------------------------------------- /Collections/IGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace Imagin.Core.Collections; 4 | 5 | public interface IGroup : IList 6 | { 7 | string Name { get; set; } 8 | } -------------------------------------------------------------------------------- /Collections/ILimit.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Collections; 2 | 3 | public interface ILimit 4 | { 5 | Limit Limit { get; } 6 | } -------------------------------------------------------------------------------- /Collections/Limit.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using Imagin.Core.Serialization; 3 | using Imagin.Core.Storage; 4 | using System; 5 | using System.Collections; 6 | using static System.Math; 7 | 8 | namespace Imagin.Core.Collections; 9 | 10 | [Serializable] 11 | public struct Limit : IEquatable 12 | { 13 | [Serializable] 14 | public enum Actions 15 | { 16 | None, 17 | Clear, 18 | ClearAndArchive, 19 | RemoveFirst, 20 | RemoveLast, 21 | } 22 | 23 | public readonly Actions Action; 24 | 25 | public readonly int Value; 26 | 27 | /// 28 | 29 | public Limit(int value, Actions action = Actions.RemoveFirst) 30 | { 31 | Value = value; 32 | Action = action; 33 | } 34 | 35 | /// 36 | 37 | public static implicit operator Limit(int i) => new(i); 38 | 39 | public static implicit operator int(Limit i) => i.Value; 40 | 41 | /// 42 | 43 | public bool Coerce(IList input) 44 | { 45 | if (input.Count > Value) 46 | { 47 | //Always >= 1 48 | var blocks = new string[Floor(input.Count.Double() / Value.Double()).Int32()]; 49 | switch (Action) 50 | { 51 | case Actions.Clear: 52 | for (var i = 0; i < (blocks.Length * Value); i++) 53 | input.RemoveAt(0); 54 | 55 | break; 56 | 57 | case Actions.ClearAndArchive: 58 | 59 | if (input is ISerialize serializer) 60 | { 61 | if (Value > 0) 62 | { 63 | for (var i = 0; i < blocks.Length; i++) 64 | { 65 | var items = new object[Value]; 66 | for (var j = 0; j < items.Length; j++) 67 | { 68 | items[j] = items[0]; 69 | input.RemoveAt(0); 70 | } 71 | 72 | blocks[i] = StoragePath.Clone(serializer.FilePath, StoragePath.DefaultCloneFormat, j => System.IO.File.Exists(j)); 73 | serializer?.Serialize(blocks[i], items); 74 | } 75 | } 76 | } 77 | else goto case Actions.Clear; 78 | break; 79 | 80 | case Actions.RemoveFirst: 81 | for (var i = 0; i < (blocks.Length * Value); i++) 82 | input.RemoveAt(0); 83 | 84 | break; 85 | 86 | case Actions.RemoveLast: 87 | for (var i = 0; i < (blocks.Length * Value); i++) 88 | input.RemoveAt(input.Count - 1); 89 | 90 | break; 91 | } 92 | return true; 93 | } 94 | return false; 95 | } 96 | 97 | /// 98 | 99 | public override string ToString() => $"{Value}"; 100 | 101 | /// 102 | 103 | public static bool operator ==(Limit left, Limit right) => left.EqualsOverload(right); 104 | 105 | public static bool operator !=(Limit left, Limit right) => !(left == right); 106 | 107 | public bool Equals(Limit i) => this.Equals(i) && Action.Equals(i.Action) && Value.Equals(i.Value); 108 | 109 | public override bool Equals(object i) => Equals((Limit)i); 110 | 111 | public override int GetHashCode() => new { Action, Value }.GetHashCode(); 112 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/ChangeCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Collections.ObjectModel; 4 | 5 | [Serializable] 6 | public class ChangeCollection : ObservableCollection, IChange 7 | { 8 | public event ChangedEventHandler Changed; 9 | 10 | [Hide] 11 | public sealed override bool ObserveItems => true; 12 | 13 | public ChangeCollection() : base() { } 14 | 15 | protected virtual void OnChanged() => Changed?.Invoke(this); 16 | 17 | protected override void OnItemChanged(System.ComponentModel.PropertyChangedEventArgs e) 18 | { 19 | base.OnItemChanged(e); 20 | OnChanged(); 21 | } 22 | 23 | public override void OnPropertyChanged(PropertyEventArgs e) 24 | { 25 | base.OnPropertyChanged(e); 26 | OnChanged(); 27 | } 28 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/GroupCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Imagin.Core.Collections.ObjectModel; 6 | 7 | [Serializable] 8 | public class GroupCollection : NamableCollection>, IGroup 9 | { 10 | public GroupCollection() : base() { } 11 | 12 | public GroupCollection(string name) : base(name) { } 13 | 14 | public GroupCollection(string name, IEnumerable items) : base(name, items.Select(i => new GroupItem(i))) { } 15 | 16 | public GroupCollection(string name, IEnumerable> items) : base(name, items) { } 17 | 18 | public void Add(string name, T item) 19 | => Add(new GroupItem(name, item)); 20 | 21 | public void Add(string name, string description, T item) 22 | => Add(new GroupItem(name, description, item)); 23 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/GroupItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Collections.ObjectModel; 4 | 5 | [Categorize(false), Serializable] 6 | public class GroupItem : Namable, IDescription, IGeneric 7 | { 8 | [Hide] 9 | public DateTime Created { get => Get(DateTime.Now); private set => Set(value); } 10 | 11 | [Index(1), Modify, Pin(Pin.AboveOrLeft), StringStyle(StringStyle.MultiLine), Vertical] 12 | public string Description { get => Get(""); set => Set(value); } 13 | 14 | [Hide] 15 | public bool IsSelected { get => Get(false); set => Set(value); } 16 | 17 | [Editable, HideName, Modify] 18 | public override T Value { get => base.Value; set => base.Value = value; } 19 | 20 | /// 21 | 22 | public GroupItem() : this("") { } 23 | 24 | public GroupItem(T value) : this("", value) { } 25 | 26 | public GroupItem(string name) : base(name) { } 27 | 28 | public GroupItem(string name, T value) : this(name) => Value = value; 29 | 30 | public GroupItem(string name, string description, T value) : this(name, value) => Description = description; 31 | 32 | /// 33 | 34 | Type IGeneric.GetGenericType() => Value is T i ? i.GetType() : typeof(T); 35 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/IItemChanged.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Collections.ObjectModel; 2 | 3 | public interface IItemChanged 4 | { 5 | bool ObserveItems { get; } 6 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/NamableCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Imagin.Core.Collections.ObjectModel; 6 | 7 | [Serializable] 8 | public class NamableCollection : ObservableCollection 9 | { 10 | public string Name { get => this.Get(""); set => this.Set(value); } 11 | 12 | public NamableCollection() : this(default, default) { } 13 | 14 | public NamableCollection(string name) : this(name, default) { } 15 | 16 | public NamableCollection(string name, IEnumerable items) : base(items ?? Enumerable.Empty()) => Name = name; 17 | 18 | public override string ToString() => Name; 19 | } -------------------------------------------------------------------------------- /Collections/ObjectModel/ObservableHistory.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core.Collections.ObjectModel; 6 | 7 | [Serializable] 8 | public class ObservableHistory : ObservableCollection, ILimit 9 | { 10 | readonly Stack redo = new(); 11 | 12 | Limit limit = default; 13 | public Limit Limit 14 | { 15 | get => limit; 16 | set 17 | { 18 | limit = value; 19 | limit.Coerce(this); 20 | } 21 | } 22 | 23 | /// 24 | 25 | T Peek() 26 | { 27 | T result = default; 28 | foreach (var i in this) 29 | result = i; 30 | 31 | return result; 32 | } 33 | 34 | T Pop() 35 | { 36 | if (Count > 0) 37 | { 38 | var result = this.Last(); 39 | Remove(result); 40 | return result; 41 | } 42 | return default; 43 | } 44 | 45 | /// 46 | 47 | new public void Add(T item) 48 | { 49 | if (Peek()?.Equals(item) != true) 50 | { 51 | base.Add(item); 52 | if (!limit.Coerce(this)) 53 | redo.Clear(); 54 | } 55 | } 56 | 57 | new public void Clear() 58 | { 59 | redo.Clear(); 60 | base.Clear(); 61 | } 62 | 63 | /// 64 | 65 | public bool CanRedo() => redo.Count > 0; 66 | 67 | public bool CanUndo() => Count > 0; 68 | 69 | /// 70 | 71 | public bool Redo(Action action) 72 | { 73 | if (CanRedo()) 74 | { 75 | var i = redo.Pop(); 76 | base.Add(i); 77 | action?.Invoke(i); 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | public bool Undo(Action action) 84 | { 85 | if (CanUndo()) 86 | { 87 | var i = Pop(); 88 | redo.Push(i); 89 | action?.Invoke(i); 90 | return true; 91 | } 92 | return false; 93 | } 94 | } 95 | 96 | [Serializable] 97 | public class StringHistory : ObservableHistory 98 | { 99 | public StringHistory(Limit limit = default) : base() 100 | { 101 | Limit = limit; 102 | } 103 | } -------------------------------------------------------------------------------- /Collections/Serialization/IWriter.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | 3 | namespace Imagin.Core.Collections.Serialization; 4 | 5 | public interface IWriter 6 | { 7 | Result Load(); 8 | 9 | Result Save(); 10 | } -------------------------------------------------------------------------------- /Conversion/IConvert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Conversion; 4 | 5 | public interface IConvert 6 | { 7 | Type InputType { get; } 8 | 9 | Type OutputType { get; } 10 | } 11 | 12 | public interface IConvert 13 | { 14 | B ConvertTo(A a); 15 | 16 | A ConvertBack(B b); 17 | } -------------------------------------------------------------------------------- /Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | Imagin.Core 6 | Imagin.Core 7 | Debug 8 | readme.md 9 | en 10 | 6.6.1.0 11 | 6.6.1.0 12 | 13 | True 14 | No rights reserved. 15 | True 16 | 17 | imagin;core;net;wpf;windows 18 | https://github.com/imagin-tech/Imagin.NET 19 | https://github.com/imagin-tech/Imagin.NET 20 | BSD-2-Clause 21 | imagin-tech 22 | Imagin 23 | 3.0.0 24 | Common elements for shared projects. 25 | Logo.png 26 | 27 | 28 | 29 | 30 | Preview 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | True 97 | \ 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Core.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | ShowAllFiles 5 | true 6 | false 7 | 8 | -------------------------------------------------------------------------------- /Core/Accessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | public class Accessor : Base 6 | { 7 | public readonly Func Get; 8 | 9 | public readonly Action Set; 10 | 11 | public T Value 12 | { 13 | get => Get(); 14 | set 15 | { 16 | Set(value); 17 | Update(() => Value); 18 | } 19 | } 20 | 21 | public Accessor(Func get, Action set) 22 | { 23 | Get = get; Set = set; 24 | } 25 | } 26 | 27 | public class BooleanAccessor : Accessor 28 | { 29 | public BooleanAccessor(Func get, Action set) : base(get, set) { } 30 | } -------------------------------------------------------------------------------- /Core/Array.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Imagin.Core; 5 | 6 | public static class Array 7 | { 8 | public static T[] New(IEnumerable input) => input.ToArray(); 9 | 10 | public static T[] New(params T[] input) => input; 11 | } -------------------------------------------------------------------------------- /Core/Attribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | public abstract class Attribute : Attribute 6 | { 7 | public readonly T Value; 8 | 9 | public Attribute(T input) : base() => Value = input; 10 | } 11 | 12 | public abstract class BindingAttribute : Attribute 13 | { 14 | public Type Converter { get; set; } 15 | 16 | public object ConverterParameter { get; set; } 17 | 18 | public string Path { get; set; } 19 | 20 | public string StringFormat { get; set; } 21 | 22 | public BindingAttribute() : base() { } 23 | } 24 | 25 | public abstract class LocalizableAttribute : Attribute 26 | { 27 | public bool Localize { get; set; } 28 | 29 | public LocalizableAttribute(bool localize = true) : base() => Localize = localize; 30 | } 31 | 32 | public abstract class TemplateAttribute : Attribute 33 | { 34 | public string Key { get; set; } 35 | 36 | public string Path { get; set; } 37 | 38 | public Type Source { get; set; } 39 | 40 | public TemplateAttribute(string path, Type source, string key) : base() 41 | { 42 | Path = path; Source = source; Key = key; 43 | } 44 | } -------------------------------------------------------------------------------- /Core/Copy.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.ObjectModel; 2 | using Imagin.Core.Linq; 3 | using System; 4 | using System.Linq; 5 | 6 | namespace Imagin.Core; 7 | 8 | /// A singleton "clipboard" that stores a single reference for each unique type. 9 | /// Instances can only be replaced once added. 10 | public class Copy 11 | { 12 | public class DataModel : Base 13 | { 14 | public Type Type { get => Get(); set => Set(value); } 15 | 16 | public DataModel() : base() { } 17 | 18 | public DataModel(Type type, object data) : base(data) => Type = type; 19 | } 20 | 21 | public static ObservableCollection Data { get; private set; } = new(); 22 | 23 | /// 24 | 25 | public static bool Contains() => Contains(typeof(T)); 26 | 27 | public static bool Contains(Type type) => type != null && Data.Contains(i => i.Type == type); 28 | 29 | /// 30 | 31 | public static T Get() => Get(typeof(T)).As(); 32 | 33 | public static object Get(Type type) => Contains(type) ? Data.FirstOrDefault(i => i.Type == type)?.Value : null; 34 | 35 | public static void Set(T input) 36 | { 37 | var type = typeof(T); 38 | 39 | if (Contains(type)) 40 | { 41 | Data.IndexOf(i => i.Type == type).If(i => i >= 0, Data.RemoveAt); 42 | Data.Add(new(type, input)); 43 | } 44 | else Data.Add(new(type, input)); 45 | } 46 | } -------------------------------------------------------------------------------- /Core/Current.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core; 6 | 7 | /// Stores a single-instance with an associated (unique) for global (indefinite) access. 8 | public static class Current 9 | { 10 | static readonly Dictionary instances = new(); 11 | 12 | /// 13 | 14 | public static void Add(T instance) 15 | { 16 | var type = instance.GetType(); 17 | if (instances.ContainsKey(type)) 18 | { 19 | instances[type] = instance; 20 | return; 21 | } 22 | instances.Add(type, instance); 23 | } 24 | 25 | public static T Create(params object[] parameters) 26 | { 27 | var result = typeof(T).Create(parameters); 28 | Add(result); 29 | return result; 30 | } 31 | 32 | public static T Get() 33 | { 34 | if (instances.ContainsKey(typeof(T))) 35 | return (T)instances[typeof(T)]; 36 | 37 | return instances.FirstOrDefault(i => i.Key.Inherits(typeof(T), true) || (typeof(T).IsInterface && i.Key.Implements())); 38 | } 39 | } -------------------------------------------------------------------------------- /Core/Handle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Imagin.Core; 5 | 6 | [Serializable] 7 | public class Handle 8 | { 9 | public delegate Task AsyncDelegate(); 10 | 11 | bool value; 12 | 13 | Handle(bool input) => value = input; 14 | 15 | public Handle() { } 16 | 17 | public static implicit operator Handle(bool input) => new(input); 18 | 19 | public void Invoke(Action action) 20 | { 21 | value = true; 22 | action(); 23 | value = false; 24 | } 25 | 26 | public void SafeInvoke(Action @unsafe, Action safe = null) 27 | { 28 | if (!value) 29 | { 30 | value = true; 31 | @unsafe(); 32 | value = false; 33 | } 34 | else safe?.Invoke(); 35 | } 36 | 37 | async public Task SafeInvokeAsync(AsyncDelegate @unsafe, AsyncDelegate safe = null) 38 | { 39 | if (!value) 40 | { 41 | value = true; 42 | await @unsafe(); 43 | value = false; 44 | } 45 | else if (safe != null) 46 | await safe(); 47 | } 48 | } -------------------------------------------------------------------------------- /Core/Instances.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core; 6 | 7 | public class Instances 8 | { 9 | readonly Dictionary instances = new(); 10 | 11 | public T this[Type input] => (T)instances.GetOrAdd(input, () => input.Create()); 12 | } 13 | 14 | public class Instances : Instances { } -------------------------------------------------------------------------------- /Core/Resource.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using Imagin.Core.Reflection; 3 | using System; 4 | 5 | namespace Imagin.Core; 6 | 7 | public static class Resource 8 | { 9 | public static Uri GetImageUri(object image) => GetUri($"Images/{image}.png", AssemblyType.Core); 10 | 11 | public static Uri GetImageUri(string fileName, AssemblyType assembly = AssemblyType.Current) => GetUri($"Images/{fileName}", assembly); 12 | 13 | public static Uri GetUri(string relativePath, AssemblyType assembly = AssemblyType.Current) => GetUri(XAssembly.GetAssemblyName(assembly), relativePath); 14 | 15 | public static Uri GetUri(string assemblyName, string relativePath) => new($"pack://application:,,,/{assemblyName};component/{relativePath}", UriKind.Absolute); 16 | } -------------------------------------------------------------------------------- /Core/Try.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | namespace Imagin.Core; 6 | 7 | public static class Try 8 | { 9 | public static Result Invoke(Action @try, Action @catch = null, Action @finally = null, bool research = false) 10 | { 11 | try 12 | { 13 | @try(); 14 | return new Success(); 15 | } 16 | catch (Exception e) 17 | { 18 | @catch?.Invoke(e); 19 | 20 | if (research) 21 | { 22 | var xcb = "http://stackoverflow.com/search?q=[c#]+" + e.Message; 23 | System.Diagnostics.Process.Start(xcb); 24 | } 25 | 26 | return new Error(e); 27 | } 28 | finally 29 | { 30 | @finally?.Invoke(); 31 | } 32 | } 33 | 34 | public static Result Invoke(out T output, Func @try, Action @catch = null, Action @finally = null, bool research = false) 35 | { 36 | T temp = default; 37 | var result = Invoke(() => temp = @try(), @catch, @finally, research); 38 | output = temp; 39 | return result; 40 | } 41 | 42 | public static async Task InvokeAsync(Action @try, Action @catch = null, Action @finally = null, bool research = false) => await Task.Run(() => Invoke(@try, @catch, @finally, research)); 43 | 44 | /// 45 | 46 | public static T Return(Func @try, Action @catch = null, Action @finally = null, bool research = false) 47 | { 48 | try 49 | { 50 | return @try(); 51 | } 52 | catch (Exception e) 53 | { 54 | @catch?.Invoke(e); 55 | 56 | if (research) 57 | { 58 | var xcb = "http://stackoverflow.com/search?q=[c#]+" + e.Message; 59 | System.Diagnostics.Process.Start(xcb); 60 | } 61 | } 62 | finally 63 | { 64 | @finally?.Invoke(); 65 | } 66 | return default; 67 | } 68 | } -------------------------------------------------------------------------------- /Core/While.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Imagin.Core; 5 | 6 | public static class While 7 | { 8 | public static async Task InvokeAsync(Func condition) { await Task.Run(() => { while (condition()) { } }); } 9 | 10 | public static async Task InvokeAsync(Func input, Predicate condition, Action onFinished = null) 11 | { 12 | await Task.Run(() => { while (condition(input())) { } }); 13 | onFinished?.Invoke(input()); 14 | } 15 | } -------------------------------------------------------------------------------- /Data/DataFolders.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public enum DataFolders 4 | { 5 | Documents, 6 | Execution, 7 | Local, 8 | Roaming 9 | } -------------------------------------------------------------------------------- /Data/SortDescription.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.ObjectModel; 2 | using System; 3 | 4 | namespace Imagin.Core.Data; 5 | 6 | [Serializable] 7 | public class SortDescription : Namable 8 | { 9 | public SortDirection Direction { get => Get(SortDirection.Ascending); set => Set(value); } 10 | 11 | public SortDescription() : this(default, default) { } 12 | 13 | public SortDescription(string name, SortDirection direction) : base(name) 14 | { 15 | Direction = direction; 16 | } 17 | } 18 | 19 | [Serializable] 20 | public class SortDescriptionCollection : ObservableCollection 21 | { 22 | public SortDescriptionCollection() : base() { } 23 | } -------------------------------------------------------------------------------- /Data/SortDirection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Data; 4 | 5 | [Serializable] 6 | public enum SortDirection 7 | { 8 | Ascending, 9 | Descending 10 | } -------------------------------------------------------------------------------- /Enum/Appearance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Flags, Serializable] 6 | public enum Appearance 7 | { 8 | None = 0, Hidden = 1, Visible = 2, 9 | All = Hidden | Visible 10 | } -------------------------------------------------------------------------------- /Enum/CardinalDirection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Serializable] 6 | public enum CardinalDirection 7 | { 8 | NW = 0, 9 | N = 1, 10 | NE = 2, 11 | W = 3, 12 | Origin = 4, 13 | E = 5, 14 | SW = 6, 15 | S = 7, 16 | SE = 8, 17 | Unknown = 9, 18 | } -------------------------------------------------------------------------------- /Enum/Exclusivity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Data; 4 | 5 | [Serializable] 6 | public enum Exclusivity 7 | { 8 | Include, Exclude 9 | } -------------------------------------------------------------------------------- /Enum/LeftRight.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Serializable] 6 | public enum LeftRight 7 | { 8 | Left, 9 | Right 10 | } -------------------------------------------------------------------------------- /Enum/Quality.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public enum Quality 4 | { 5 | Perfect, Excellent, Average, Fair, Poor 6 | } -------------------------------------------------------------------------------- /Enum/RelativeDirection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Flags] 6 | [Serializable] 7 | public enum RelativeDirection 8 | { 9 | None = 0, 10 | Up = 1, 11 | Down = 2, 12 | Left = 4, 13 | Right = 8, 14 | All = Up | Down | Left | Right 15 | } -------------------------------------------------------------------------------- /Enum/TopBottom.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Serializable] 6 | public enum TopBottom 7 | { 8 | Top, 9 | Bottom 10 | } -------------------------------------------------------------------------------- /Enum/Types.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [Serializable] 6 | public enum Types 7 | { 8 | Reference, 9 | Value 10 | } -------------------------------------------------------------------------------- /Input/BooleanEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Input; 2 | 3 | public delegate void BooleanEventHandler(bool input); -------------------------------------------------------------------------------- /Input/CanceledEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Input; 2 | 3 | public delegate void CancelEventHandler(object sender, CancelEventArgs e); 4 | 5 | public class CancelEventArgs : EventArgs 6 | { 7 | public bool Cancel { get; set; } 8 | 9 | public CancelEventArgs(T input) : base(input) { } 10 | } -------------------------------------------------------------------------------- /Input/ChangedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Input; 4 | 5 | public delegate void ChangedEventHandler(object sender, ChangedEventArgs e); 6 | 7 | public class ChangedEventArgs : EventArgs 8 | { 9 | public readonly T NewValue; 10 | 11 | public readonly T OldValue; 12 | 13 | public ChangedEventArgs(T oldValue, T newValue) : base() 14 | { 15 | OldValue = oldValue; 16 | NewValue = newValue; 17 | } 18 | } -------------------------------------------------------------------------------- /Input/CheckedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Input; 4 | 5 | public delegate void CheckedEventHandler(object sender, CheckedEventArgs e); 6 | 7 | public class CheckedEventArgs : EventArgs 8 | { 9 | public readonly bool? State; 10 | 11 | public CheckedEventArgs(bool? state) : base() => State = state; 12 | } 13 | -------------------------------------------------------------------------------- /Input/DefaultEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Input; 4 | 5 | public delegate void DefaultEventHandler(object sender, EventArgs e); 6 | 7 | public class EventArgs : EventArgs 8 | { 9 | readonly T _value; 10 | public T Value => _value; 11 | 12 | readonly object _parameter; 13 | public object Parameter => _parameter; 14 | 15 | public EventArgs(T value, object parameter = null) 16 | { 17 | _value = value; 18 | _parameter = parameter; 19 | } 20 | } -------------------------------------------------------------------------------- /Input/LockedEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Input; 4 | 5 | public delegate void LockedEventHandler(object sender, LockedEventArgs e); 6 | 7 | public class LockedEventArgs : EventArgs 8 | { 9 | public readonly bool IsLocked; 10 | 11 | public LockedEventArgs(bool isLocked) : base() => IsLocked = isLocked; 12 | } -------------------------------------------------------------------------------- /Input/Modified.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Input; 4 | 5 | public class ModifiedEventArgs : EventArgs 6 | { 7 | public readonly object OriginalSource; 8 | 9 | public readonly object OldValue; 10 | 11 | public readonly object NewValue; 12 | 13 | public readonly string PropertyName; 14 | 15 | public ModifiedEventArgs(object originalSource, string propertyName, object oldValue, object newValue) : base() 16 | { 17 | OriginalSource = originalSource; PropertyName = propertyName; OldValue = oldValue; NewValue = newValue; 18 | } 19 | } 20 | 21 | public delegate void ModifiedEventHandler(object sender, ModifiedEventArgs e); -------------------------------------------------------------------------------- /Input/SelectedEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Input; 2 | 3 | public delegate void SelectedEventHandler(object sender, SelectedEventArgs e); 4 | 5 | public class SelectedEventArgs : EventArgs 6 | { 7 | public SelectedEventArgs(object value) : base(value) { } 8 | 9 | public SelectedEventArgs(object value, object parameter) : base(value, parameter) { } 10 | } 11 | -------------------------------------------------------------------------------- /Input/WeakEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Reflection; 7 | 8 | namespace Imagin.Core.Input; 9 | 10 | public class WeakEvent 11 | { 12 | readonly List handlers; 13 | 14 | public WeakEvent() => handlers = new List(); 15 | 16 | public void Raise(object sender, TEventArgs e) 17 | { 18 | lock (handlers) 19 | { 20 | handlers.RemoveAll(h => !h.Invoke(sender, e)); 21 | } 22 | } 23 | 24 | public void Subscribe(EventHandler handler) 25 | { 26 | var weakHandlers = handler 27 | .GetInvocationList() 28 | .Select(d => new WeakDelegate(d)) 29 | .ToList(); 30 | 31 | lock (handlers) 32 | { 33 | handlers.AddRange(weakHandlers); 34 | } 35 | } 36 | 37 | public void Unsubscribe(EventHandler handler) 38 | { 39 | lock (handlers) 40 | { 41 | int index = handlers.FindIndex(h => h.IsMatch(handler)); 42 | if (index >= 0) 43 | handlers.RemoveAt(index); 44 | } 45 | } 46 | 47 | class WeakDelegate 48 | { 49 | #region Open handler generation and cache 50 | 51 | delegate void OpenEventHandler(object target, object sender, TEventArgs e); 52 | 53 | // ReSharper disable once StaticMemberInGenericType (by design) 54 | static readonly ConcurrentDictionary _openHandlerCache = 55 | new(); 56 | 57 | static OpenEventHandler CreateOpenHandler(MethodInfo method) 58 | { 59 | var target = Expression.Parameter(typeof(object), "target"); 60 | var sender = Expression.Parameter(typeof(object), "sender"); 61 | var e = Expression.Parameter(typeof(TEventArgs), "e"); 62 | 63 | if (method.IsStatic) 64 | { 65 | var expr = Expression.Lambda( 66 | Expression.Call( 67 | method, 68 | sender, e), 69 | target, sender, e); 70 | return expr.Compile(); 71 | } 72 | else 73 | { 74 | var expr = Expression.Lambda( 75 | Expression.Call( 76 | Expression.Convert(target, method.DeclaringType), 77 | method, 78 | sender, e), 79 | target, sender, e); 80 | return expr.Compile(); 81 | } 82 | } 83 | 84 | #endregion 85 | 86 | readonly MethodInfo method; 87 | 88 | readonly OpenEventHandler openHandler; 89 | 90 | readonly WeakReference weakTarget; 91 | 92 | public WeakDelegate(Delegate handler) 93 | { 94 | weakTarget = handler.Target != null ? new WeakReference(handler.Target) : null; 95 | method = handler.GetMethodInfo(); 96 | openHandler = _openHandlerCache.GetOrAdd(method, CreateOpenHandler); 97 | } 98 | 99 | public bool Invoke(object sender, TEventArgs e) 100 | { 101 | object target = null; 102 | if (weakTarget != null) 103 | { 104 | target = weakTarget.Target; 105 | if (target == null) 106 | return false; 107 | } 108 | openHandler(target, sender, e); 109 | return true; 110 | } 111 | 112 | public bool IsMatch(EventHandler handler) 113 | { 114 | return ReferenceEquals(handler.Target, weakTarget?.Target) 115 | && handler.GetMethodInfo().Equals(method); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Interface/IChange.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public delegate void ChangedEventHandler(object sender); 4 | 5 | /// Specifies an that changes. 6 | public interface IChange 7 | { 8 | /// Occurs when the changes. 9 | event ChangedEventHandler Changed; 10 | } -------------------------------------------------------------------------------- /Interface/ICheck.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | /// 4 | /// Specifies an with a checkable state. 5 | /// 6 | public interface ICheck 7 | { 8 | /// 9 | /// 10 | /// 11 | bool? IsChecked 12 | { 13 | get; set; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Interface/IContainer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Imagin.Core; 4 | 5 | public interface IContainer 6 | { 7 | IList Items { get; } 8 | } -------------------------------------------------------------------------------- /Interface/IDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Imagin.Core; 6 | 7 | /// Specifies an with a description. 8 | public interface IDescription 9 | { 10 | string Description { get; set; } 11 | } -------------------------------------------------------------------------------- /Interface/IEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | public interface IEntry 6 | { 7 | DateTime Date 8 | { 9 | get; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Interface/IFind.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IFind 4 | { 5 | int CaretIndex { get; set; } 6 | 7 | int SelectionLength { get; set; } 8 | 9 | int SelectionStart { get; set; } 10 | 11 | string Text { get; set; } 12 | } -------------------------------------------------------------------------------- /Interface/IGeneric.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | public interface IGeneric 6 | { 7 | Type GetGenericType(); 8 | } -------------------------------------------------------------------------------- /Interface/ILock.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | 3 | namespace Imagin.Core; 4 | 5 | /// 6 | /// Specifies an that can be locked and unlocked. 7 | /// 8 | public interface ILock 9 | { 10 | event LockedEventHandler Locked; 11 | 12 | bool IsLocked 13 | { 14 | get; set; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Interface/IModify.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | 3 | namespace Imagin.Core; 4 | 5 | public interface IModify 6 | { 7 | event ModifiedEventHandler Modified; 8 | } -------------------------------------------------------------------------------- /Interface/IName.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | /// Specifies an with a name. 4 | public interface IName 5 | { 6 | string Name { get; set; } 7 | } -------------------------------------------------------------------------------- /Interface/IParse.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IParse 4 | { 5 | object Parse(string input); 6 | } 7 | -------------------------------------------------------------------------------- /Interface/IPropertyChanged.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.Generic; 2 | using System; 3 | using System.ComponentModel; 4 | 5 | namespace Imagin.Core; 6 | 7 | /// Notifies clients that a property value has changed. 8 | /// Implements . 9 | public interface IPropertyChanged : INotifyPropertyChanged 10 | { 11 | ObjectDictionary SerializedProperties { get; } 12 | 13 | ObjectDictionary NonSerializedProperties { get; } 14 | 15 | /// Occurs when a property value changes. 16 | void OnPropertyChanged(PropertyEventArgs e); 17 | 18 | /// Occurs before a property changes. 19 | void OnPropertyChanging(PropertyChangingEventArgs e); 20 | 21 | /// Occurs when a property value is requested. 22 | void OnPropertyGet(GetPropertyEventArgs e); 23 | } 24 | 25 | public class PropertyEventArgs : EventArgs 26 | { 27 | public readonly string PropertyName; 28 | 29 | public readonly object OldValue; 30 | 31 | public object NewValue { get; set; } 32 | 33 | public PropertyEventArgs(string propertyName, object oldValue, object newValue) : base() 34 | { 35 | PropertyName = propertyName; 36 | OldValue = oldValue; NewValue = newValue; 37 | } 38 | } 39 | 40 | public class PropertyChangingEventArgs : PropertyEventArgs 41 | { 42 | public bool Cancel { get; set; } = false; 43 | 44 | public PropertyChangingEventArgs(string propertyName, object oldValue, object newValue) : base(propertyName, oldValue, newValue) { } 45 | } 46 | 47 | public class GetPropertyEventArgs : EventArgs 48 | { 49 | public readonly string PropertyName; 50 | 51 | public object Value { get; set; } 52 | 53 | public GetPropertyEventArgs(string propertyName, object value) : base() { PropertyName = propertyName; Value = value; } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Interface/IRange.Generic.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IRange 4 | { 5 | T Maximum { get; } 6 | 7 | T Minimum { get; } 8 | } -------------------------------------------------------------------------------- /Interface/IRange.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IRange 4 | { 5 | object Increment { get; set; } 6 | 7 | object Maximum { get; set; } 8 | 9 | object Minimum { get; set; } 10 | } -------------------------------------------------------------------------------- /Interface/IReset.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IReset 4 | { 5 | void Reset(); 6 | } -------------------------------------------------------------------------------- /Interface/IRotate.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | /// Specifies something has a rotation. 4 | public interface IRotate { double Rotation { get; set; } } -------------------------------------------------------------------------------- /Interface/ISelect.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | 3 | namespace Imagin.Core 4 | { 5 | /// 6 | /// Specifies an that can be selected. 7 | /// 8 | public interface ISelect 9 | { 10 | event SelectedEventHandler Selected; 11 | 12 | bool IsSelected 13 | { 14 | get; set; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Interface/ISubscribe.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface ISubscribe 4 | { 5 | void Subscribe(); 6 | } -------------------------------------------------------------------------------- /Interface/IUnsubscribe.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public interface IUnsubscribe 4 | { 5 | void Unsubscribe(); 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Developed by Imagin. No rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Linq/Array.Generic.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static partial class XArray 7 | { 8 | public static T[] Add(this T[] input, params T[] elements) 9 | { 10 | var length = input.Length; 11 | System.Array.Resize(ref input, length + elements.Length); 12 | 13 | for (int j = 0, count = elements.Length; j < count; j++) 14 | input[length + j] = elements[j]; 15 | 16 | return input; 17 | } 18 | 19 | /// 20 | 21 | public static T[,] Duplicate(this T[,] input) 22 | { 23 | int rows = input.GetLength(0), columns = input.GetLength(1); 24 | 25 | var result = new T[rows, columns]; 26 | for (int row = 0; row < rows; row++) 27 | { 28 | for (int column = 0; column < columns; column++) 29 | result[row, column] = input[row, column]; 30 | } 31 | return result; 32 | } 33 | 34 | public static T[][] Duplicate(this T[][] input) 35 | { 36 | int rows = input.Length, columns = input[0].Length; 37 | 38 | var result = new T[rows][]; 39 | for (int row = 0; row < rows; row++) 40 | { 41 | result[row] = new T[columns]; 42 | for (int column = 0; column < columns; column++) 43 | result[row][column] = input[row][column]; 44 | } 45 | return result; 46 | } 47 | 48 | /// 49 | 50 | public static T[] Empty() => new T[0]; 51 | 52 | /// 53 | 54 | public static int IndexOf(this T[] input, T element) 55 | { 56 | for (int i = 0, length = input.Length; i < length; i++) 57 | { 58 | if (input[i].Equals(element)) 59 | return i; 60 | } 61 | return -1; 62 | } 63 | 64 | /// 65 | 66 | public static T[] New(params T[] input) => input ?? new T[0]; 67 | 68 | public static T[] New(IEnumerable input) 69 | { 70 | var count = input?.Count() ?? 0; 71 | var result = new T[count]; 72 | 73 | if (count == 0) 74 | return result; 75 | 76 | for (var i = 0; i < count; i++) 77 | result[i] = input.ElementAtOrDefault(i); 78 | 79 | return result; 80 | } 81 | 82 | /// 83 | 84 | public static T[][] Project(this T[,] input) 85 | { 86 | int rows = input.GetLength(0), columns = input.GetLength(1); 87 | 88 | var result = new T[rows][]; 89 | for (int row = 0; row < rows; row++) 90 | { 91 | result[row] = new T[columns]; 92 | for (int column = 0; column < columns; column++) 93 | result[row][column] = input[row, column]; 94 | } 95 | 96 | return result; 97 | } 98 | 99 | public static T[,] Project(this T[][] input) 100 | { 101 | int rows = input.Length, columns = input[0].Length; 102 | 103 | var result = new T[rows, columns]; 104 | for (int row = 0; row < rows; row++) 105 | { 106 | for (int column = 0; column < columns; column++) 107 | result[row, column] = input[row][column]; 108 | } 109 | 110 | return result; 111 | } 112 | 113 | /// 114 | 115 | public static void Remove(this T[] input, params T[] elements) 116 | { 117 | foreach (var i in elements) 118 | input.RemoveAt(input.IndexOf(i)); 119 | } 120 | 121 | public static void RemoveAt(this T[] input, int index) 122 | { 123 | var result = new T[input.Length - 1]; 124 | 125 | if (index > 0) 126 | System.Array.Copy(input, 0, result, 0, index); 127 | 128 | if (index < input.Length - 1) 129 | System.Array.Copy(input, index + 1, result, index, input.Length - index - 1); 130 | 131 | input = result; 132 | } 133 | } -------------------------------------------------------------------------------- /Linq/Array.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static partial class XArray 7 | { 8 | public static T Compare(this T[] input, Func action, T origin) 9 | { 10 | T result = origin; 11 | foreach (var i in input) 12 | { 13 | if (action(i, result)) 14 | result = i; 15 | } 16 | return result; 17 | } 18 | 19 | /// 20 | 21 | /// Gets the largest value. 22 | public static decimal Largest(this decimal[] input) => Compare(input, (i, j) => i > j, decimal.MinValue); 23 | 24 | /// Gets the largest value. 25 | public static double Largest(this double[] input) => Compare(input, (i, j) => i > j, double.MinValue); 26 | 27 | /// Gets the largest value. 28 | public static short Largest(this short[] input) => Compare(input, (i, j) => i > j, short.MinValue); 29 | 30 | /// Gets the largest value. 31 | public static int Largest(this int[] input) => Compare(input, (i, j) => i > j, int.MinValue); 32 | 33 | /// Gets the largest value. 34 | public static long Largest(this long[] input) => Compare(input, (i, j) => i > j, long.MinValue); 35 | 36 | /// Gets the largest value. 37 | public static ushort Largest(this ushort[] input) => Compare(input, (i, j) => i > j, ushort.MinValue); 38 | 39 | /// Gets the largest value. 40 | public static uint Largest(this uint[] input) => Compare(input, (i, j) => i > j, uint.MinValue); 41 | 42 | /// Gets the largest value. 43 | public static ulong Largest(this ulong[] input) => Compare(input, (i, j) => i > j, ulong.MinValue); 44 | 45 | /// Gets the largest value. 46 | public static float Largest(this float[] input) => Compare(input, (i, j) => i > j, float.MinValue); 47 | 48 | /// 49 | 50 | /// Gets the largest value. 51 | public static decimal Smallest(this decimal[] input) => Compare(input, (i, j) => i < j, decimal.MaxValue); 52 | 53 | /// Gets the largest value. 54 | public static double Smallest(this double[] input) => Compare(input, (i, j) => i < j, double.MaxValue); 55 | 56 | /// Gets the largest value. 57 | public static short Smallest(this short[] input) => Compare(input, (i, j) => i < j, short.MaxValue); 58 | 59 | /// Gets the largest value. 60 | public static int Smallest(this int[] input) => Compare(input, (i, j) => i < j, int.MaxValue); 61 | 62 | /// Gets the largest value. 63 | public static long Smallest(this long[] input) => Compare(input, (i, j) => i < j, long.MaxValue); 64 | 65 | /// Gets the largest value. 66 | public static ushort Smallest(this ushort[] input) => Compare(input, (i, j) => i < j, ushort.MaxValue); 67 | 68 | /// Gets the largest value. 69 | public static uint Smallest(this uint[] input) => Compare(input, (i, j) => i < j, uint.MaxValue); 70 | 71 | /// Gets the largest value. 72 | public static ulong Smallest(this ulong[] input) => Compare(input, (i, j) => i < j, ulong.MaxValue); 73 | 74 | /// Gets the largest value. 75 | public static float Smallest(this float[] input) => Compare(input, (i, j) => i < j, float.MaxValue); 76 | 77 | /// 78 | 79 | public static string SplitWith(this Array input, string separator) 80 | { 81 | var result = string.Empty; 82 | 83 | var k = 0; 84 | foreach (var j in input) 85 | { 86 | result += $"{j}"; 87 | 88 | if (k < input.Length - 1) 89 | result += $"{separator}"; 90 | 91 | k++; 92 | } 93 | 94 | return result; 95 | } 96 | 97 | public static IEnumerable Where(this Array value, Predicate predicate) 98 | { 99 | foreach (var i in value) 100 | { 101 | if (predicate(i)) 102 | yield return i; 103 | } 104 | yield break; 105 | } 106 | } -------------------------------------------------------------------------------- /Linq/Assembly.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using Imagin.Core.Reflection; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | 8 | namespace Imagin.Core.Linq; 9 | 10 | public static class XAssembly 11 | { 12 | static readonly Dictionary Assemblies = new(); 13 | 14 | /// 15 | 16 | public const string BaseName = "Imagin.Core"; 17 | 18 | public const string Name = BaseName + ".WPF"; 19 | 20 | /// 21 | 22 | public static Assembly GetAssembly(string assemblyName) => GetProperties(assemblyName).Assembly; 23 | 24 | public static Assembly GetAssembly(AssemblyType input) => GetAssembly(GetAssemblyName(input)); 25 | 26 | public static string GetAssemblyName(AssemblyType input) 27 | { 28 | return input switch 29 | { 30 | AssemblyType.Color => BaseName + ".Color", 31 | AssemblyType.Core => Name, 32 | AssemblyType.Current => GetProperties(null).Name, 33 | AssemblyType.Shared => BaseName, 34 | _ => throw new NotSupportedException() 35 | }; 36 | } 37 | 38 | /// 39 | 40 | public static AssemblyInfo GetProperties(AssemblyType input) => GetProperties(GetAssemblyName(input)); 41 | 42 | public static AssemblyInfo GetProperties(string assemblyName) 43 | { 44 | assemblyName ??= Assembly.GetEntryAssembly().GetName().Name; 45 | if (!Assemblies.ContainsKey(assemblyName)) 46 | Assemblies.Add(assemblyName, new(assemblyName)); 47 | 48 | return Assemblies[assemblyName]; 49 | } 50 | 51 | /// 52 | 53 | public static IEnumerable GetDerivedTypes(AssemblyType assembly, bool ignoreAbstract = true, bool ignoreHidden = true) 54 | => GetAssembly(assembly).GetDerivedTypes(ignoreAbstract, ignoreHidden); 55 | 56 | public static IEnumerable GetDerivedTypes(this Assembly assembly, bool ignoreAbstract = true, bool ignoreHidden = true) 57 | => assembly.GetDerivedTypes(null, ignoreAbstract, ignoreHidden); 58 | 59 | public static IEnumerable GetDerivedTypes(this Assembly assembly, string namePath, bool ignoreAbstract = true, bool ignoreHidden = true) 60 | { 61 | var result = from type in assembly.GetTypes() 62 | where 63 | ( 64 | ((type.IsClass && type.Inherits(true)) || (typeof(T).IsInterface && type.Implements())) 65 | && 66 | (namePath == null || type.Namespace == namePath) 67 | && 68 | (!ignoreAbstract || !type.IsAbstract) 69 | && 70 | (!ignoreHidden || !type.HasAttribute()) 71 | ) 72 | select type; 73 | foreach (var i in result) 74 | yield return i; 75 | } 76 | 77 | /// 78 | 79 | public static IEnumerable GetTypes(this Assembly input, string namePath, Predicate where = null) 80 | => from type in input.GetTypes() where type.Namespace == namePath && @where?.Invoke(type) == true select type; 81 | 82 | public static IEnumerable GetTypes(AssemblyType assembly, string namePath, Predicate where = null) => GetAssembly(assembly).GetTypes(namePath, where); 83 | } -------------------------------------------------------------------------------- /Linq/Boolean.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XBoolean 6 | { 7 | public static void If(this bool a, bool b, Action @if, Action @else = null) 8 | { 9 | if (a == b) 10 | @if(); 11 | 12 | else @else?.Invoke(); 13 | } 14 | } -------------------------------------------------------------------------------- /Linq/Bullets.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | using Imagin.Core.Text; 3 | using System; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static class XBullets 8 | { 9 | public static object ToString(this Bullets input, double index) 10 | { 11 | Try.Invoke(out object result, () => 12 | { 13 | var i = index.Int32(); 14 | return input switch 15 | { 16 | Bullets.LetterUpperPeriod 17 | => $"{Number.Convert(i, Numerics.NumberStyle.Letter)}.".ToUpper(), 18 | Bullets.LetterUpperParenthesis 19 | => $"{Number.Convert(i, Numerics.NumberStyle.Letter)})".ToUpper(), 20 | Bullets.LetterLowerPeriod 21 | => $"{Number.Convert(i, Numerics.NumberStyle.Letter)}.".ToLower(), 22 | Bullets.LetterLowerParenthesis 23 | => $"{Number.Convert(i, Numerics.NumberStyle.Letter)})".ToLower(), 24 | Bullets.NumberPeriod 25 | => $"{index}.", 26 | Bullets.NumberParenthesis 27 | => $"{index})", 28 | Bullets.RomanNumberUpperPeriod 29 | => $"{Number.Convert(i, Numerics.NumberStyle.Roman)}.".ToUpper(), 30 | Bullets.RomanNumberUpperParenthesis 31 | => $"{Number.Convert(i, Numerics.NumberStyle.Roman)})".ToUpper(), 32 | Bullets.RomanNumberLowerPeriod 33 | => $"{Number.Convert(i, Numerics.NumberStyle.Roman)}.".ToLower(), 34 | Bullets.RomanNumberLowerParenthesis 35 | => $"{Number.Convert(i, Numerics.NumberStyle.Roman)})".ToLower(), 36 | _ => throw new NotSupportedException(), 37 | }; 38 | }); 39 | return result; 40 | } 41 | } -------------------------------------------------------------------------------- /Linq/Double.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XDouble 6 | { 7 | public static double Abs(this double value) 8 | => System.Math.Abs(value); 9 | 10 | public static double Ceiling(this double value) 11 | => System.Math.Ceiling(value); 12 | 13 | public static double NaN(this double input, double j) => double.IsNaN(input) ? j : input; 14 | 15 | public static double Floor(this double value) 16 | => System.Math.Floor(value); 17 | 18 | public static double Round(this double value, int digits = 0) 19 | => System.Math.Round(value, digits); 20 | 21 | /// Gets a representing the given number of days. 22 | public static TimeSpan Days(this double input) => TimeSpan.FromDays(input); 23 | 24 | /// Gets a representing the given number of hours. 25 | public static TimeSpan Hours(this double input) => TimeSpan.FromHours(input); 26 | 27 | /// Gets a representing the given number of milliseconds. 28 | public static TimeSpan Milliseconds(this double input) => TimeSpan.FromMilliseconds(input); 29 | 30 | /// Gets a representing the given number of minutes. 31 | public static TimeSpan Minutes(this double input) => TimeSpan.FromMinutes(input); 32 | 33 | /// Gets a representing the given number of months. 34 | public static TimeSpan Months(this double input) => TimeSpan.FromDays(30 * input); 35 | 36 | /// Gets a representing the given number of seconds. 37 | public static TimeSpan Seconds(this double input) => TimeSpan.FromSeconds(input); 38 | 39 | /// Gets a representing the given number of years. 40 | public static TimeSpan Years(this double input) => TimeSpan.FromDays(365 * input); 41 | } -------------------------------------------------------------------------------- /Linq/Enum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static class XEnum 8 | { 9 | public static Enum AddFlag(this System.Enum input, Enum value) where Enum : struct, IFormattable, IComparable, IConvertible => (Enum)System.Enum.ToObject(typeof(Enum), input.To() | value.To()); 10 | 11 | public static Enum AddFlag(this Enum input, Enum value) => Enum.ToObject(input.GetType(), input.To() | value.To()) as Enum; 12 | 13 | /// 14 | 15 | public static T GetAttribute(this Enum input) where T : Attribute => input.GetAttribute(typeof(T)) as T; 16 | 17 | public static Attribute GetAttribute(this Enum input, Type attribute) 18 | { 19 | var info = input.GetType().GetMember($"{input}"); 20 | if (info?.Length > 0) 21 | return info[0].GetCustomAttributes(true).FirstOrDefault(i => i.As().GetType() is Type j && ((attribute.IsInterface && j.Implements(attribute)) || j.Inherits(attribute, true))); 22 | 23 | return default; 24 | } 25 | 26 | public static T[] GetAttributes(this Enum input) where T : Attribute 27 | { 28 | var info = input.GetType().GetMember(input.ToString()); 29 | if (info?.Length == 1) 30 | { 31 | var result = info[0].GetCustomAttributes(true).Where(i => i is T); 32 | return result.Count() > 0 ? result.Cast().ToArray() : null; 33 | } 34 | return default; 35 | } 36 | 37 | public static IEnumerable GetAttributes(this Enum input) 38 | { 39 | var info = input.GetType().GetMember(input.ToString()); 40 | return info[0].GetCustomAttributes(true).Cast() ?? Enumerable.Empty(); 41 | } 42 | 43 | /// 44 | 45 | public static bool HasAttribute(this Enum input) where Attribute : System.Attribute => input.HasAttribute(typeof(Attribute)); 46 | 47 | public static bool HasAttribute(this Enum input, Type attribute) => input.GetAttribute(attribute) != null; 48 | 49 | /// 50 | 51 | public static string GetDescription(this Enum input) => input?.GetAttribute()?.Description ?? input?.GetAttribute()?.Description; 52 | 53 | public static string GetDisplayName(this Enum input) => input?.GetAttribute()?.DisplayName ?? input?.GetAttribute()?.Name; 54 | 55 | public static string GetLargeImage(this Enum input) => input?.GetAttribute()?.LargeImage; 56 | 57 | public static string GetSmallImage(this Enum input) => input?.GetAttribute()?.SmallImage; 58 | 59 | /// 60 | 61 | public static bool HasAllFlags(this Enum input, params Enum[] values) 62 | { 63 | foreach (var i in values) 64 | { 65 | if (!input.HasFlag(i)) 66 | return false; 67 | } 68 | return true; 69 | } 70 | 71 | public static bool HasAnyFlags(this Enum input, params Enum[] values) 72 | { 73 | foreach (var i in values) 74 | { 75 | if (input.HasFlag(i)) 76 | return true; 77 | } 78 | return false; 79 | } 80 | 81 | public static bool HasNoFlags(this Enum input, params Enum[] values) 82 | { 83 | return !input.HasAnyFlags(values); 84 | } 85 | 86 | /// 87 | 88 | public static bool IsHidden(this Enum input) 89 | => input.GetAttribute()?.Browsable == false || input.HasAttribute(); 90 | 91 | /// 92 | 93 | public static Enum RemoveFlag(this System.Enum input, Enum value) where Enum : struct, IFormattable, IComparable, IConvertible 94 | => (Enum)System.Enum.ToObject(typeof(Enum), input.To() & ~value.To()); 95 | 96 | public static Enum RemoveFlag(this Enum input, Enum value) 97 | => Enum.ToObject(input.GetType(), input.To() & ~value.To()) as Enum; 98 | } -------------------------------------------------------------------------------- /Linq/Expression.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static class XExpression 7 | { 8 | public static string GetMemberName(this Expression> input) => input.Body.As().Member.Name; 9 | } -------------------------------------------------------------------------------- /Linq/ICollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XCollection 6 | { 7 | public static bool Contains(this ICollection input, object i) 8 | { 9 | foreach (var j in input) 10 | { 11 | if (j.Equals(i)) 12 | return true; 13 | } 14 | return false; 15 | } 16 | } -------------------------------------------------------------------------------- /Linq/ICommand.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XCommand 6 | { 7 | public static void Execute(this ICommand input) => input.Execute(null); 8 | } -------------------------------------------------------------------------------- /Linq/IDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static class XDictionary 8 | { 9 | public static Z FirstOrDefault(this Dictionary input, Predicate> where = null) 10 | { 11 | foreach (var i in input) 12 | { 13 | if (i.Value is Z result) 14 | { 15 | if (where == null || where.Invoke(i)) 16 | return result; 17 | } 18 | } 19 | return default; 20 | } 21 | 22 | public static object GetOrAdd(this IDictionary input, object key, Func defaultValue = null) 23 | { 24 | if (key != null) 25 | { 26 | if (!input.Contains(key)) 27 | input.Add(key, defaultValue?.Invoke()); 28 | 29 | return input[key]; 30 | } 31 | return null; 32 | } 33 | 34 | public static void SetOrAdd(this IDictionary input, object key, T value) 35 | { 36 | if (key != null) 37 | { 38 | if (!input.Contains(key)) 39 | input.Add(key, value); 40 | 41 | input[key] = value; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Linq/IEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static partial class XEnumerable 8 | { 9 | public static bool Empty(this IEnumerable input) 10 | { 11 | foreach (var i in input) 12 | return false; 13 | 14 | return true; 15 | } 16 | 17 | public static void ForEach(this IEnumerable input, Action action) 18 | { 19 | foreach (var i in input) 20 | action(i); 21 | } 22 | 23 | public static object First(this IEnumerable input) 24 | { 25 | foreach (var i in input) 26 | return i; 27 | 28 | return null; 29 | } 30 | 31 | public static T FirstOrDefault(this IEnumerable input) 32 | { 33 | if (input != null) 34 | { 35 | foreach (var i in input) 36 | { 37 | if (i is T j) 38 | return j; 39 | } 40 | } 41 | return default; 42 | } 43 | 44 | public static object Last(this IEnumerable input) 45 | { 46 | object result = default; 47 | input.ForEach(i => result = i); 48 | return result; 49 | } 50 | 51 | public static IEnumerable Select(this IEnumerable input, Func action) 52 | { 53 | foreach (var i in input) 54 | yield return action(i); 55 | } 56 | } -------------------------------------------------------------------------------- /Linq/IList.Generic.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace Imagin.Core.Linq; 7 | 8 | public static partial class XList 9 | { 10 | public static void AddSorted(this IList input, T item, IComparer comparer = null) 11 | { 12 | if (comparer == null) 13 | comparer = Comparer.Default; 14 | 15 | int i = 0; 16 | while (i < input.Count && comparer.Compare(input[i], item) < 0) 17 | i++; 18 | 19 | input.Insert(i, item); 20 | } 21 | 22 | public static T First(this IList input) => input.Any() ? input[0] : default; 23 | 24 | public static void For(this IList input, int from, Action, int> action) 25 | { 26 | for (var i = from; i < input.Count(); i++) 27 | action(input, i); 28 | } 29 | 30 | public static void For(this IList input, int from, int until, Action, int> action) 31 | { 32 | for (var i = from; i < until; i++) 33 | action(input, i); 34 | } 35 | 36 | public static void For(this IList input, int from, Predicate until, Action, int> action) 37 | { 38 | for (var i = from; until(i); i++) 39 | action(input, i); 40 | } 41 | 42 | public static int IndexOf(this IList input, Predicate where) 43 | { 44 | var result = 0; 45 | foreach (var i in input) 46 | { 47 | if (i is T j) 48 | { 49 | if (where(j)) 50 | return result; 51 | } 52 | result++; 53 | } 54 | return -1; 55 | } 56 | 57 | public static T Last(this IList input) => input.Any() ? input[input.Count - 1] : default; 58 | 59 | public static void Remove(this IList input, Predicate where) 60 | { 61 | for (var i = input.Count - 1; i >= 0; i--) 62 | { 63 | if (where(input[i])) 64 | input.Remove(input[i]); 65 | } 66 | } 67 | 68 | public static void Shuffle(this IList input) 69 | { 70 | int n = input.Count; 71 | while (n > 1) 72 | { 73 | n--; 74 | int k = Numerics.Random.NextInt32(n + 1); 75 | T value = input[k]; 76 | input[k] = input[n]; 77 | input[n] = value; 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /Linq/IMatrix.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XMatrix 6 | { 7 | /// Converts all values into a range of [0, 1] based on the smallest and largest occurring value (the current range). 8 | public static Matrix Normalize(this IMatrix input) => input.Normalize(out Range _); 9 | 10 | /// Converts all values into a range of [0, 1] based on the smallest and largest occurring value (the current range). 11 | public static Matrix Normalize(this IMatrix input, out Range range) 12 | { 13 | var result = new Matrix(input.Values); 14 | 15 | var smallest = result.Smallest(); var largest = result.Largest(); 16 | if (smallest == largest) 17 | smallest = largest - 1; 18 | 19 | var r = new DoubleRange(smallest, largest); 20 | 21 | int rows = result.Rows, columns = result.Columns; 22 | for (var y = 0; y < rows; y++) 23 | { 24 | for (var x = 0; x < columns; x++) 25 | input.Values[y][x] = r.Convert(0, 1, input.Values[y][x]); 26 | } 27 | 28 | range = new(smallest, largest); 29 | return result; 30 | } 31 | } -------------------------------------------------------------------------------- /Linq/IRange.Generic.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Linq; 2 | 3 | public static partial class XRange 4 | { 5 | /// Converts the given value to a new range based on the current range. 6 | public static double Convert(this IRange input, in IRange range, in double value) => input.Convert(range.Minimum, range.Maximum, value); 7 | 8 | /// Converts the given value to a new range based on the current range. 9 | public static double Convert(this IRange input, in double min, in double max, in double value) 10 | { 11 | var n = (max - min) / (input.Maximum - input.Minimum); 12 | return min + ((value - input.Minimum) * n); 13 | } 14 | 15 | /// Converts the given value to a new range based on the current range. 16 | public static float Convert(this IRange input, in float min, in float max, in float value) 17 | { 18 | var n = (max - min) / (input.Maximum - input.Minimum); 19 | return min + ((value - input.Minimum) * n); 20 | } 21 | } -------------------------------------------------------------------------------- /Linq/IVector.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | using System; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static class XVector 7 | { 8 | /// Gets an absolute . 9 | public static Vector Absolute(this IVector input) => input.Transform((i, j) => j.Abs()); 10 | 11 | /// Coerces the range of the based on the specified range. 12 | public static Vector Clamp(this IVector input, double minimum, double maximum) => input.Transform((i, j) => M.Clamp(j, maximum, minimum)); 13 | 14 | /// Coerces the range of the based on the specified range. 15 | public static Vector Clamp(this IVector input, Vector minimum, Vector maximum) 16 | { 17 | if (minimum.Length != input.Length) 18 | throw new ArgumentOutOfRangeException(nameof(minimum)); 19 | 20 | if (maximum.Length != input.Length) 21 | throw new ArgumentOutOfRangeException(nameof(maximum)); 22 | 23 | return input.Transform((index, value) => M.Clamp(value, maximum[index], minimum[index])); 24 | } 25 | 26 | /// Performs dot multiplication on both given vectors. 27 | public static double Dot(this IVector left, IVector right) 28 | { 29 | double result = 0; 30 | left.Each((i, j) => result += j * right.Values[i]); 31 | return result; 32 | } 33 | 34 | /// Calls the given action for each value in the vector. 35 | public static void Each(this IVector input, Action action) 36 | { 37 | for (int i = 0, count = input.Values.Length; i < count; i++) 38 | action(i, input.Values[i]); 39 | } 40 | 41 | /// Gets the largest value in the vector. 42 | public static double Largest(this IVector input) => input.Values.Largest(); 43 | 44 | /// Gets a rounded copy. 45 | public static Vector Round(this IVector input) => input.Transform((i, j) => j.Round()); 46 | 47 | /// Gets the smallest value in the vector. 48 | public static double Smallest(this IVector input) => input.Values.Smallest(); 49 | 50 | /// Gets the sum of all values in the vector. 51 | public static double Sum(this IVector input) 52 | { 53 | double result = 0; 54 | input.Values.ForEach(i => result += i); 55 | return result; 56 | } 57 | } -------------------------------------------------------------------------------- /Linq/Int32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XInt32 6 | { 7 | /// Gets a representing the given number of days. 8 | public static TimeSpan Days(this int input) => TimeSpan.FromDays(input); 9 | 10 | /// Gets a representing the given number of hours. 11 | public static TimeSpan Hours(this int input) => TimeSpan.FromHours(input); 12 | 13 | /// Gets a representing the given number of milliseconds. 14 | public static TimeSpan Milliseconds(this int input) => TimeSpan.FromMilliseconds(input); 15 | 16 | /// Gets a representing the given number of minutes. 17 | public static TimeSpan Minutes(this int input) => TimeSpan.FromMinutes(input); 18 | 19 | /// Gets a representing the given number of months. 20 | public static TimeSpan Months(this int input) => TimeSpan.FromDays(30 * input); 21 | 22 | /// Gets a representing the given number of seconds. 23 | public static TimeSpan Seconds(this int input) => TimeSpan.FromSeconds(input); 24 | 25 | /// Gets a representing the given number of years. 26 | public static TimeSpan Years(this int input) => TimeSpan.FromDays(365 * input); 27 | } -------------------------------------------------------------------------------- /Linq/MemberInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static class XMemberInfo 8 | { 9 | public static bool CanGet(this MemberInfo input) => input is FieldInfo field ? field.CanGet() : input is PropertyInfo property ? property.CanGet() : false; 10 | 11 | public static bool CanGet(this FieldInfo input) => input.IsPublic; 12 | 13 | public static bool CanGet(this PropertyInfo input) => input.CanRead && input.GetGetMethod(true) != null; 14 | 15 | /// 16 | 17 | public static bool CanSet(this MemberInfo input) => input is FieldInfo field ? field.CanSet() : input is PropertyInfo property ? property.CanSet() : false; 18 | 19 | public static bool CanSet(this FieldInfo input) => !input.IsInitOnly && input.IsPublic; 20 | 21 | public static bool CanSet(this PropertyInfo input) => input.CanWrite && input.GetSetMethod(true) != null; 22 | 23 | /// 24 | 25 | public static T GetAttribute(this MemberInfo input) where T : Attribute 26 | { 27 | foreach (var i in input.GetCustomAttributes(true)) 28 | { 29 | if (i is T j) 30 | return j; 31 | } 32 | return default; 33 | } 34 | 35 | public static IEnumerable GetAttributes(this MemberInfo input) where T : Attribute 36 | { 37 | foreach (var i in input.GetCustomAttributes(true)) 38 | { 39 | if (i is T j) 40 | yield return j; 41 | } 42 | yield break; 43 | } 44 | 45 | public static IEnumerable GetAttributes(this MemberInfo input) => input.GetAttributes(); 46 | 47 | /// 48 | 49 | public static string GetCategory(this MemberInfo input, string empty = "Other") 50 | => input.GetAttribute()?.Category?.ToString() ?? input.GetAttribute()?.Category ?? empty; 51 | 52 | public static string GetDescription(this MemberInfo input) 53 | => input.GetAttribute()?.Description ?? input.GetAttribute()?.Description ?? ""; 54 | 55 | public static string GetDisplayName(this MemberInfo input) 56 | => input.GetAttribute()?.Name ?? input.GetAttribute()?.DisplayName ?? input.Name; 57 | 58 | /// 59 | 60 | public static Type GetMemberType(this MemberInfo input) => input is FieldInfo field ? field.FieldType : input is PropertyInfo property ? property.PropertyType : null; 61 | 62 | /// 63 | 64 | public static bool HasAttribute(this MemberInfo input) => input.HasAttribute(typeof(T)); 65 | 66 | public static bool HasAttribute(this MemberInfo input, Type type) 67 | { 68 | foreach (var i in input.GetCustomAttributes(true)) 69 | { 70 | if (i.GetType().Inherits(type, true)) 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | /// 77 | 78 | public static bool IsHidden(this MemberInfo input) 79 | => input.GetAttribute()?.Browsable == false || input.HasAttribute(); 80 | 81 | public static bool IsIndexor(this MemberInfo input) 82 | => input is PropertyInfo property && property.GetIndexParameters()?.Length > 0; 83 | 84 | public static bool IsSerializable(this MemberInfo input) 85 | => !input.HasAttribute() && !input.HasAttribute() && !input.HasAttribute(); 86 | 87 | public static bool IsStatic(this MemberInfo input) 88 | => (input is FieldInfo field && field.IsStatic) || (input is PropertyInfo property && property.GetAccessors(true)[0].IsStatic); 89 | } -------------------------------------------------------------------------------- /Linq/MethodInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XMethodInfo 6 | { 7 | public static bool IsEvent(this MethodInfo method) => (method.Name.StartsWith("add") || method.Name.StartsWith("remove")) && method.IsSpecialName; 8 | 9 | public static bool IsGetter(this MethodInfo method) => method.Name.StartsWith("get") && method.IsSpecialName; 10 | 11 | public static bool IsSetter(this MethodInfo method) => method.Name.StartsWith("set") && method.IsSpecialName; 12 | } -------------------------------------------------------------------------------- /Linq/Object.Generic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static partial class XObject 7 | { 8 | #region Equals 9 | 10 | /* Remarks 11 | 12 | To implement equality in a class, define the following methods and tweak accordingly... 13 | 14 | A. public static bool operator ==(T a, T b) => a.EqualsOverload(b); 15 | B. public static bool operator !=(T a, T b) => !(a == b); 16 | C. public override bool Equals(object b) => Equals(b as T); 17 | D. public bool Equals(T b) => this.Equals(b) && ...; 18 | E. public override int GetHashCode() => ...; 19 | 20 | */ 21 | 22 | /// 23 | /// Implements for any given that implements . 24 | /// 25 | /// 26 | /// 27 | /// 28 | /// 29 | public static bool Equals(this T a, T b) 30 | { 31 | if (ReferenceEquals(b, null)) 32 | return false; 33 | 34 | if (ReferenceEquals(a, b)) 35 | return true; 36 | 37 | if (a.GetType() != b.GetType()) 38 | return false; 39 | 40 | return true; 41 | } 42 | 43 | /// 44 | /// Implements the operator for any given or . Example: 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// 50 | public static bool EqualsOverload(this T a, T b) 51 | { 52 | if (ReferenceEquals(a, null)) 53 | { 54 | //null == null = true 55 | if (ReferenceEquals(b, null)) 56 | return true; 57 | 58 | //Only the left side is null 59 | return false; 60 | } 61 | return a.Equals(b); 62 | } 63 | 64 | #endregion 65 | 66 | /// 67 | 68 | /// 69 | /// Calls the given action if the object is not . 70 | /// 71 | public static void If(this T input, Action isNotNull, Action isNull = null) 72 | { 73 | if (input is T i) 74 | isNotNull(i); 75 | 76 | else isNull?.Invoke(); 77 | } 78 | 79 | /// 80 | /// Calls the given action if the object is and satisfies the given predicate. 81 | /// 82 | public static void If(this T input, Predicate where, Action isNotNull, Action isNull = null) 83 | { 84 | if (input is T i) 85 | { 86 | if (where(i)) 87 | isNotNull(i); 88 | 89 | return; 90 | } 91 | isNull?.Invoke(); 92 | } 93 | 94 | /// 95 | 96 | public static void If(this T input, T ifEquals, Action thenDo, Action elseDo = null) 97 | => input.If(ifEquals, i => thenDo(), i => elseDo()); 98 | 99 | public static void If(this T input, T ifEquals, Action thenDo, Action elseDo = null) 100 | { 101 | if (EqualityComparer.Default.Equals(input, ifEquals)) 102 | { 103 | thenDo(input); 104 | } 105 | else elseDo(input); 106 | } 107 | 108 | /// 109 | 110 | /// Calls the given action if the object is . 111 | public static Output IfGet(this Input input, Func get) 112 | { 113 | if (input is Input i) 114 | return get(i); 115 | 116 | return default; 117 | } 118 | 119 | /// Calls the given action if the object satisfies the given predicate. 120 | public static Output IfGet(this Input input, Predicate where, Func get) 121 | { 122 | if (where(input)) 123 | return get(input); 124 | 125 | return default; 126 | } 127 | } -------------------------------------------------------------------------------- /Linq/Stack.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XStack 6 | { 7 | public static bool Any(this Stack input) => input.Count > 0; 8 | } -------------------------------------------------------------------------------- /Linq/Stream.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XStream 6 | { 7 | public static byte[] Array(this Stream input) 8 | { 9 | using var result = new MemoryStream(); 10 | input.CopyTo(result); 11 | return result.ToArray(); 12 | } 13 | } -------------------------------------------------------------------------------- /Linq/TimeSpan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using static System.Math; 4 | 5 | namespace Imagin.Core.Linq; 6 | 7 | public static class XTimeSpan 8 | { 9 | public static TimeSpan Clamp(this TimeSpan input, TimeSpan maximum, TimeSpan minimum = default) 10 | { 11 | var result = minimum == default ? TimeSpan.Zero : minimum; 12 | return input > maximum ? maximum : (input < result ? result : input); 13 | } 14 | 15 | public static TimeSpan Left(this TimeSpan input, long current, long total) 16 | { 17 | var lines = (current.Double() / total.Double()) * 100; 18 | lines = lines == 0.0 ? 1.0 : lines; 19 | var seconds = (input.TotalSeconds / lines) * (100.0 - lines); 20 | return TimeSpan.FromSeconds(double.IsNaN(seconds) ? 0 : seconds); 21 | } 22 | 23 | public static int Months(this TimeSpan input) => Floor(input.Days.Double() / 30).Int32(); 24 | 25 | public static string ShortTime(this TimeSpan input, bool daysOnly) 26 | { 27 | if (input.TotalSeconds == 0) 28 | return string.Empty; 29 | 30 | string result = string.Empty; 31 | if (input.Days > 0) 32 | result += string.Format("{0}d", input.Days.ToString()); 33 | 34 | if (!daysOnly || input.Days == 0) 35 | { 36 | if (input.Hours > 0) 37 | result += string.Format(" {0}h", input.Hours.ToString()); 38 | 39 | if (input.Minutes > 0) 40 | result += string.Format(" {0}m", input.Minutes.ToString()); 41 | 42 | if (input.Seconds > 0) 43 | result += string.Format(" {0}s", input.Seconds.ToString()); 44 | } 45 | 46 | return result; 47 | } 48 | 49 | async public static Task TrySleep(this TimeSpan input) => await Task.Run(() => Try.Invoke(() => System.Threading.Thread.Sleep(input.TotalMilliseconds.Int32()), e => Analytics.Log.Write(e))); 50 | 51 | public static int Years(this TimeSpan input) 52 | { 53 | var result = input.Months(); 54 | return result >= 12 ? Floor(result.Double() / 12).Int32() : 0; 55 | } 56 | } -------------------------------------------------------------------------------- /Linq/TimeZone.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | using System; 3 | 4 | namespace Imagin.Core.Linq; 5 | 6 | public static class XTimeZone 7 | { 8 | /// 9 | /// Gets the current time based on the given time zone. 10 | /// 11 | /// 12 | /// 13 | public static DateTime Now(this Time.TimeZone input) 14 | { 15 | var result = DateTime.UtcNow; 16 | result = TimeZoneInfo.ConvertTimeFromUtc(result, TimeZoneInfo.FindSystemTimeZoneById($"{input}".SplitCamel())); 17 | return result; 18 | } 19 | 20 | /// 21 | /// Tries to get the current time based on the given time zone. 22 | /// 23 | public static Result TryNow(this Time.TimeZone input, out DateTime result) 24 | { 25 | DateTime internalResult = default; 26 | var finalResult = Try.Invoke(() => internalResult = input.Now(), i => Log.Write(i)); 27 | result = internalResult; 28 | return finalResult; 29 | } 30 | } -------------------------------------------------------------------------------- /Linq/Unit.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XUnit 6 | { 7 | /// Converts the given value from (a) to (b). 8 | public static double Convert(this Unit a, Unit b, double value, double ppi = 72.0) 9 | { 10 | var pixels = 0d; 11 | switch (a) 12 | { 13 | case Unit.Pixel: 14 | pixels = System.Math.Round(value, 0); 15 | break; 16 | case Unit.Inch: 17 | pixels = System.Math.Round(value * ppi, 0); 18 | break; 19 | case Unit.Centimeter: 20 | pixels = System.Math.Round((value * ppi) / 2.54, 0); 21 | break; 22 | case Unit.Millimeter: 23 | pixels = System.Math.Round((value * ppi) / 25.4, 0); 24 | break; 25 | case Unit.Point: 26 | pixels = System.Math.Round((value * ppi) / 72, 0); 27 | break; 28 | case Unit.Pica: 29 | pixels = System.Math.Round((value * ppi) / 6, 0); 30 | break; 31 | case Unit.Twip: 32 | pixels = System.Math.Round((value * ppi) / 1140, 0); 33 | break; 34 | case Unit.Character: 35 | pixels = System.Math.Round((value * ppi) / 12, 0); 36 | break; 37 | case Unit.En: 38 | pixels = System.Math.Round((value * ppi) / 144.54, 0); 39 | break; 40 | } 41 | 42 | var inches = pixels / ppi; 43 | var result = pixels; 44 | 45 | switch (b) 46 | { 47 | case Unit.Inch: 48 | result = inches; 49 | break; 50 | case Unit.Centimeter: 51 | result = inches * 2.54; 52 | break; 53 | case Unit.Millimeter: 54 | result = inches * 25.4; 55 | break; 56 | case Unit.Point: 57 | result = inches * 72.0; 58 | break; 59 | case Unit.Pica: 60 | result = inches * 6.0; 61 | break; 62 | case Unit.Twip: 63 | result = inches * 1140.0; 64 | break; 65 | case Unit.Character: 66 | result = inches * 12.0; 67 | break; 68 | case Unit.En: 69 | result = inches * 144.54; 70 | break; 71 | } 72 | 73 | return result; 74 | } 75 | } -------------------------------------------------------------------------------- /Linq/Version.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Linq; 4 | 5 | public static class XVersion 6 | { 7 | public static Version Coerce(this Version input, Version maximum, Version minimum) => input > maximum ? maximum : (input < minimum ? minimum : input); 8 | } -------------------------------------------------------------------------------- /Local/CultureAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Local; 4 | 5 | [AttributeUsage(AttributeTargets.Field)] 6 | public class CultureAttribute : Attribute 7 | { 8 | public readonly string Code; 9 | 10 | public CultureAttribute(string code) : base() => Code = code; 11 | } -------------------------------------------------------------------------------- /Local/Language.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Local; 4 | 5 | [Serializable] 6 | public enum Language 7 | { 8 | [Culture("en")] 9 | English, 10 | [Culture("fr-FR")] 11 | French, 12 | [Culture("it-IT")] 13 | Italian, 14 | [Culture("ja-JP")] 15 | Japanese 16 | } -------------------------------------------------------------------------------- /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ionsharp/Core/f6084d83c6c759a3ca68e50f5bbeba005d99c1bf/Logo.png -------------------------------------------------------------------------------- /Models/ViewModel.Generic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Models; 4 | 5 | /// 6 | [Serializable] 7 | public class ViewModel : ViewModel 8 | { 9 | public virtual T View 10 | { 11 | get => Get(default); 12 | set => Set(value); 13 | } 14 | 15 | protected ViewModel() : base() { } 16 | 17 | public ViewModel(T view) : this() => View = view; 18 | } -------------------------------------------------------------------------------- /Models/ViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Models; 4 | 5 | /// 6 | [Serializable] 7 | public class ViewModel : Base 8 | { 9 | public ViewModel() : base() { } 10 | } 11 | 12 | /// 13 | [Serializable] 14 | public class NamableViewModel : Namable 15 | { 16 | public NamableViewModel() : base() { } 17 | } 18 | 19 | /// 20 | [Serializable] 21 | public class LockableViewModel : Lockable 22 | { 23 | public LockableViewModel() : base() { } 24 | } -------------------------------------------------------------------------------- /Numerics/Angle.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public struct Angle : IEquatable 8 | { 9 | /// Specifies the largest possible value (359). 10 | public readonly static double MaxValue = 359; 11 | 12 | /// Specifies the smallest possible value (-359). 13 | public readonly static double MinValue = -359; 14 | 15 | readonly double Value; 16 | 17 | /// 18 | 19 | /// 20 | /// Initializes an instance of the structure. 21 | /// 22 | /// 23 | public Angle(double input) 24 | { 25 | if (input < MinValue || input > MaxValue) 26 | throw new NotSupportedException(); 27 | 28 | Value = input; 29 | } 30 | 31 | /// 32 | 33 | public static implicit operator double(Angle i) => i.Value; 34 | 35 | public static implicit operator Angle(double i) => new(i); 36 | 37 | /// 38 | 39 | public static bool operator <(Angle a, Angle b) => a.Value < b.Value; 40 | 41 | public static bool operator >(Angle a, Angle b) => a.Value > b.Value; 42 | 43 | public static bool operator <=(Angle a, Angle b) => a.Value <= b.Value; 44 | 45 | public static bool operator >=(Angle a, Angle b) => a.Value >= b.Value; 46 | 47 | public static Angle operator +(Angle a, Angle b) => a.Value + b.Value; 48 | 49 | public static Angle operator -(Angle a, Angle b) => a.Value - b.Value; 50 | 51 | public static Angle operator /(Angle a, Angle b) => a.Value / b.Value; 52 | 53 | public static Angle operator *(Angle a, Angle b) => a.Value * b.Value; 54 | 55 | /// 56 | 57 | public static bool operator ==(Angle a, Angle b) => a.EqualsOverload(b); 58 | 59 | public static bool operator !=(Angle a, Angle b) => !(a == b); 60 | 61 | /// 62 | 63 | public bool Equals(Angle i) 64 | => this.Equals(i) && Value.Equals(i.Value); 65 | 66 | public override bool Equals(object i) 67 | => Equals((Angle)i); 68 | 69 | public override int GetHashCode() => Value.GetHashCode(); 70 | 71 | /// 72 | 73 | public static Angle Parse(string input) => double.Parse(input); 74 | 75 | public static bool TryParse(string input, out Angle result) 76 | { 77 | var r = double.TryParse(input, out double d); 78 | result = d; 79 | return r; 80 | } 81 | 82 | /// 83 | 84 | public string ToString(string format) => Value.ToString(format); 85 | 86 | public override string ToString() => Value.ToString(); 87 | 88 | /// 89 | 90 | public static double GetDegree(double radian) => radian * (180.0 / Math.PI); 91 | 92 | public static double GetRadian(double degree) => (Math.PI / 180.0) * degree; 93 | 94 | /// 95 | 96 | public static double NormalizeDegree(double degree) 97 | { 98 | var result = degree % 360.0; 99 | return result >= 0 ? result : (result + 360.0); 100 | } 101 | } -------------------------------------------------------------------------------- /Numerics/AngleUnit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies a unit of measurement unique to angles. 6 | [Serializable] 7 | public enum AngleUnit 8 | { 9 | /// 10 | /// Specifies a degree as the unit of measure. 11 | /// 12 | [Abbreviation("°")] 13 | [Description("Specifies a degree as the unit of measure.")] 14 | Degree, 15 | /// 16 | /// Specifies a radian as the unit of measure. 17 | /// 18 | [Abbreviation("rad")] 19 | [Description("Specifies a radian as the unit of measure.")] 20 | Radian 21 | } -------------------------------------------------------------------------------- /Numerics/Axis2D.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies an axis in 2-dimensional space. 6 | [Serializable] 7 | public enum Axis2D 8 | { 9 | /// The X-axis. 10 | X, 11 | /// The Y-axis. 12 | Y 13 | } -------------------------------------------------------------------------------- /Numerics/Axis3D.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies an axis in 3-dimensional space. 6 | [Serializable] 7 | public enum Axis3D 8 | { 9 | /// The X-axis. 10 | X, 11 | /// The Y-axis. 12 | Y, 13 | /// The Z-axis. 14 | Z 15 | } -------------------------------------------------------------------------------- /Numerics/Dimensions.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Reflection; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | /// Specifies a dimension with n [1, 3] axes. 7 | [Serializable] 8 | public enum Dimensions 9 | { 10 | /// Specifies a dimension with 1 axis (X). 11 | [Image("Dimension1.png", AssemblyType.Core), Name("1D")] 12 | One, 13 | /// Specifies a dimension with 2 axes (X|Y). 14 | [Image("Dimension2.png", AssemblyType.Core), Name("2D")] 15 | Two, 16 | /// Specifies a dimension with 3 axes (X|Y|Z). 17 | [Image("Dimension3.png", AssemblyType.Core), Name("3D")] 18 | Three 19 | } -------------------------------------------------------------------------------- /Numerics/Formulas.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Apps.Desktop; 2 | 3 | public enum Formulas { None, Largest, Mean, Median, Mode, Smallest, StandardDeviation, Variance } -------------------------------------------------------------------------------- /Numerics/IMatrix.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | public interface IMatrix { double[][] Values { get; } } -------------------------------------------------------------------------------- /Numerics/IPoint2.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | public interface IPoint2 4 | { 5 | Point2 Position { get; set; } 6 | } -------------------------------------------------------------------------------- /Numerics/ISize.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | /// Specifies something has . 4 | public interface ISize 5 | { 6 | DoubleSize Size { get; set; } 7 | } -------------------------------------------------------------------------------- /Numerics/IVector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | public interface IVector 6 | { 7 | int Length { get; } 8 | 9 | double[] Values { get; } 10 | 11 | Vector Transform(Func action); 12 | } -------------------------------------------------------------------------------- /Numerics/Line.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public struct Line : IEquatable> 8 | { 9 | public static Line Default = new(default); 10 | 11 | /// 12 | 13 | public readonly T X1; 14 | 15 | public readonly T X2; 16 | 17 | public readonly T Y1; 18 | 19 | public readonly T Y2; 20 | 21 | /// 22 | 23 | public Line(T i) : this(i, i, i, i) { } 24 | 25 | public Line(T x1, T y1, T x2, T y2) 26 | { 27 | X1 = x1; 28 | Y1 = y1; 29 | X2 = x2; 30 | Y2 = y2; 31 | } 32 | 33 | /// 34 | 35 | public override string ToString() => $"{nameof(X1)} = {X1}, {nameof(Y1)} = {Y1}, {nameof(X2)} = {X2}, {nameof(Y2)} = {Y2}"; 36 | 37 | /// 38 | 39 | public static bool operator ==(Line left, Line right) => left.EqualsOverload(right); 40 | 41 | public static bool operator !=(Line left, Line right) 42 | { 43 | return !(left == right); 44 | } 45 | 46 | public bool Equals(Line i) => this.Equals>(i) && X1.Equals(i.X1) && X2.Equals(i.X2) && Y1.Equals(i.Y1) && Y2.Equals(i.Y2); 47 | 48 | public override bool Equals(object i) => i is Line j ? Equals(j) : false; 49 | 50 | public override int GetHashCode() => new { X1, Y1, X2, Y2 }.GetHashCode(); 51 | } -------------------------------------------------------------------------------- /Numerics/LineCollection.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Imagin.Core.Numerics; 7 | 8 | [Serializable] 9 | public class LineCollection : List> 10 | { 11 | public static LineCollection Empty = new(); 12 | } 13 | 14 | [Serializable] 15 | public class Int32LineCollection : LineCollection 16 | { 17 | public Int32LineCollection() : base() { } 18 | 19 | /// 20 | 21 | public override int GetHashCode() 22 | { 23 | unchecked 24 | { 25 | var hash = 19; 26 | foreach (var i in this) 27 | hash = hash * 31 + i.GetHashCode(); 28 | 29 | return hash; 30 | } 31 | } 32 | 33 | public static bool operator ==(Int32LineCollection a, Int32LineCollection b) => a.EqualsOverload(b); 34 | 35 | public static bool operator !=(Int32LineCollection a, Int32LineCollection b) => !(a == b); 36 | 37 | public bool Equals(Int32LineCollection i) 38 | { 39 | if (this.Equals(i)) 40 | { 41 | if (Count == i.Count) 42 | { 43 | for (var j = 0; j < Count; j++) 44 | { 45 | if (this[j] != i[j]) 46 | return false; 47 | } 48 | return true; 49 | } 50 | } 51 | return false; 52 | } 53 | 54 | public override bool Equals(object i) => Equals(i as Int32LineCollection); 55 | 56 | public override string ToString() 57 | { 58 | var result = new StringBuilder(); 59 | foreach (var i in this) 60 | result.AppendLine($"Line: {i}"); 61 | 62 | return result.ToString(); 63 | } 64 | } -------------------------------------------------------------------------------- /Numerics/MLine.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MLine : Base, IChange, ICloneable, IEquatable> 8 | { 9 | public event ChangedEventHandler Changed; 10 | 11 | /// 12 | 13 | public virtual Vector2 Distance { get; } 14 | 15 | /// 16 | 17 | public T X1 { get => Get(); set => Set(value); } 18 | 19 | public T Y1 { get => Get(); set => Set(value); } 20 | 21 | public T X2 { get => Get(); set => Set(value); } 22 | 23 | public T Y2 { get => Get(); set => Set(value); } 24 | 25 | /// 26 | 27 | public MLine() : base() { } 28 | 29 | public MLine(T x1, T y1, T x2, T y2) : this() 30 | { 31 | X1 = x1; 32 | Y1 = y1; 33 | X2 = x2; 34 | Y2 = y2; 35 | } 36 | 37 | /// 38 | 39 | public override void OnPropertyChanged(PropertyEventArgs e) 40 | { 41 | base.OnPropertyChanged(e); 42 | Changed?.Invoke(this); 43 | } 44 | 45 | public override string ToString() => $"{nameof(X1)} = {X1}, {nameof(Y1)} = {Y1}, {nameof(X2)} = {X2}, {nameof(Y2)} = {Y2}"; 46 | 47 | /// 48 | 49 | public MLine Clone() => new(X1, Y1, X2, Y2); 50 | object ICloneable.Clone() => Clone(); 51 | 52 | /// 53 | 54 | public static bool operator ==(MLine left, MLine right) => left.EqualsOverload(right); 55 | 56 | public static bool operator !=(MLine left, MLine right) => !(left == right); 57 | 58 | public bool Equals(MLine i) => this.Equals>(i) && X1.Equals(i.X1) && X2.Equals(i.X2) && Y1.Equals(i.Y1) && Y2.Equals(i.Y2); 59 | 60 | public override bool Equals(object i) => Equals(i as MLine); 61 | 62 | public override int GetHashCode() => new { X1, Y1, X2, Y2 }.GetHashCode(); 63 | } 64 | 65 | [Serializable] 66 | public class DoubleLine : MLine 67 | { 68 | public override Vector2 Distance => new(X1 > X2 ? X1 - X2 : X1 < X2 ? X2 - X1 : 0, Y1 > Y2 ? Y1 - Y2 : Y1 < Y2 ? Y2 - Y1 : 0); 69 | 70 | public DoubleLine(double x1, double y1, double x2, double y2) : base(x1, y1, x2, y2) { } 71 | } 72 | 73 | [Serializable] 74 | public class Int32Line : MLine 75 | { 76 | public override Vector2 Distance => new(X1 > X2 ? X1 - X2 : X1 < X2 ? X2 - X1 : 0, Y1 > Y2 ? Y1 - Y2 : Y1 < Y2 ? Y2 - Y1 : 0); 77 | 78 | public Int32Line(int x1, int y1, int x2, int y2) : base(x1, y1, x2, y2) { } 79 | } -------------------------------------------------------------------------------- /Numerics/MRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | [Serializable] 6 | public class MRange : Base, IRange 7 | { 8 | public T Minimum { get => Get(); set => Set(value); } 9 | 10 | public T Maximum { get => Get(); set => Set(value); } 11 | 12 | public MRange() : base() { } 13 | 14 | public MRange(T minimum, T maximum) : base() 15 | { 16 | Minimum = minimum; 17 | Maximum = maximum; 18 | } 19 | } 20 | 21 | [Serializable] 22 | public class AngleRange : MRange 23 | { 24 | public AngleRange() : base() { } 25 | 26 | public AngleRange(Angle minimum, Angle maximum) : base(minimum, maximum) { } 27 | } 28 | 29 | [Serializable] 30 | public class DoubleRange : MRange 31 | { 32 | public DoubleRange() : base() { } 33 | 34 | public DoubleRange(double minimum, double maximum) : base(minimum, maximum) { } 35 | } -------------------------------------------------------------------------------- /Numerics/MRegion.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MRegion : Base, IChange, ICloneable, IEquatable> 8 | { 9 | [field: NonSerialized] 10 | public event ChangedEventHandler Changed; 11 | 12 | /// 13 | 14 | public T X { get => Get(); set => Set(value); } 15 | 16 | public T Y { get => Get(); set => Set(value); } 17 | 18 | public T Height { get => Get(); set => Set(value); } 19 | 20 | public T Width { get => Get(); set => Set(value); } 21 | 22 | /// 23 | 24 | public MRegion() : base() { } 25 | 26 | public MRegion(T x, T y, T width, T height) : this() 27 | { 28 | X = x; 29 | Y = y; 30 | Width = width; 31 | Height = height; 32 | } 33 | 34 | /// 35 | 36 | public override void OnPropertyChanged(PropertyEventArgs e) 37 | { 38 | base.OnPropertyChanged(e); 39 | Changed?.Invoke(this); 40 | } 41 | 42 | public override string ToString() => $"{nameof(X)} = {X}, {nameof(Y)} = {Y}, {nameof(Height)} = {Height}, {nameof(Width)} = {Width}"; 43 | 44 | /// 45 | 46 | public MRegion Clone() => new(X, Y, Width, Height); 47 | object ICloneable.Clone() => Clone(); 48 | 49 | /// 50 | 51 | public static bool operator ==(MRegion left, MRegion right) => left.EqualsOverload(right); 52 | 53 | public static bool operator !=(MRegion left, MRegion right) => !(left == right); 54 | 55 | public bool Equals(MRegion i) => this.Equals>(i) && X.Equals(i.X) && Y.Equals(i.Y) && Height.Equals(i.Height) && Width.Equals(i.Width); 56 | 57 | public override bool Equals(object i) => Equals(i as MRegion); 58 | 59 | public override int GetHashCode() => new { X, Y, Height, Width }.GetHashCode(); 60 | } 61 | 62 | [Serializable] 63 | public class Int32Region : MRegion 64 | { 65 | public Vector2 TopLeft => new(X, Y); 66 | 67 | public Vector2 TopRight => new(X + Width, Y); 68 | 69 | public Vector2 BottomLeft => new(X, Y + Height); 70 | 71 | public Vector2 BottomRight => new(X + Width, Y + Height); 72 | 73 | public Vector2 Center => new(X + (Width / 2.0).Int32(), Y - (Height / 2.0).Int32()); 74 | 75 | public Int32Region() : this(default, default, default, default) { } 76 | 77 | public Int32Region(int x, int y, int width, int height) : base(x, y, width, height) { } 78 | 79 | public static implicit operator Int32Region(int i) => new(i, i, i, i); 80 | } 81 | 82 | [Serializable] 83 | public class DoubleRegion : MRegion 84 | { 85 | public Vector2 TopLeft => new(X, Y); 86 | 87 | public Vector2 TopRight => new(X + Width, Y); 88 | 89 | public Vector2 BottomLeft => new(X, Y + Height); 90 | 91 | public Vector2 BottomRight => new(X + Width, Y + Height); 92 | 93 | public Vector2 Center => new(X + (Width / 2.0), Y - (Height / 2.0)); 94 | 95 | public DoubleRegion() : this(default, default, default, default) { } 96 | 97 | public DoubleRegion(double x, double y, double width, double height) : base(x, y, width, height) { } 98 | 99 | public static implicit operator DoubleRegion(double i) => new(i, i, i, i); 100 | } -------------------------------------------------------------------------------- /Numerics/MSize.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MSize : Base, IChange, ICloneable, IEquatable> 8 | { 9 | public event ChangedEventHandler Changed; 10 | 11 | /// 12 | 13 | public T Height { get => Get(); set => Set(value); } 14 | 15 | public T Width { get => Get(); set => Set(value); } 16 | 17 | /// 18 | 19 | public MSize() : this(default) { } 20 | 21 | public MSize(T input) : this(input, input) { } 22 | 23 | public MSize(T height, T width) : base() 24 | { 25 | Height = height; 26 | Width = width; 27 | } 28 | 29 | /// 30 | 31 | public override void OnPropertyChanged(PropertyEventArgs e) 32 | { 33 | base.OnPropertyChanged(e); 34 | Changed?.Invoke(this); 35 | } 36 | 37 | public override string ToString() => $"{nameof(Height)} = {Height}, {nameof(Width)} = {Width}"; 38 | 39 | /// 40 | 41 | public MSize Clone() => new(Width, Height); 42 | object ICloneable.Clone() => Clone(); 43 | 44 | /// 45 | 46 | public static bool operator ==(MSize left, MSize right) => left.EqualsOverload(right); 47 | 48 | public static bool operator !=(MSize left, MSize right) => !(left == right); 49 | 50 | public bool Equals(MSize i) => this.Equals>(i) && Height.Equals(i.Height) && Width.Equals(i.Width); 51 | 52 | public override bool Equals(object i) => Equals(i as MSize); 53 | 54 | public override int GetHashCode() => new { Height, Width }.GetHashCode(); 55 | } 56 | 57 | [Serializable] 58 | public class Int32Size : MSize 59 | { 60 | public Int32Size() : base() { } 61 | 62 | public Int32Size(int input) : base(input) { } 63 | 64 | public Int32Size(int height, int width) : base(height, width) { } 65 | 66 | /// 67 | 68 | public static Int32Size operator +(Int32Size left, double right) => new((left.Height + right).Int32(), (left.Width + right).Int32()); 69 | 70 | public static Int32Size operator -(Int32Size left, double right) => new((left.Height - right).Int32(), (left.Width - right).Int32()); 71 | 72 | public static Int32Size operator *(Int32Size left, double right) => new((left.Height * right).Int32(), (left.Width * right).Int32()); 73 | 74 | public static Int32Size operator /(Int32Size left, double right) => new((left.Height / right).Int32(), (left.Width / right).Int32()); 75 | 76 | /// 77 | 78 | public Int32Size Resize(SizeProperty field, int value) 79 | { 80 | int oldHeight = Height, oldWidth = Width, newHeight = 0, newWidth = 0; 81 | switch (field) 82 | { 83 | case SizeProperty.Height: 84 | newHeight = value; 85 | newWidth = (newHeight.Double() / (oldHeight.Double() / oldWidth.Double())).Int32(); 86 | break; 87 | 88 | case SizeProperty.Width: 89 | newWidth = value; 90 | newHeight = (newWidth.Double() * (oldHeight.Double() / oldWidth.Double())).Int32(); 91 | break; 92 | } 93 | return new Int32Size(newHeight, newWidth); 94 | } 95 | } 96 | 97 | [Categorize(false), Serializable] 98 | public class DoubleSize : MSize 99 | { 100 | public DoubleSize() : base() { } 101 | 102 | public DoubleSize(double input) : base(input) { } 103 | 104 | public DoubleSize(double height, double width) : base(height, width) { } 105 | 106 | /// 107 | 108 | public static DoubleSize operator +(DoubleSize left, double right) => new(left.Height + right, left.Width + right); 109 | 110 | public static DoubleSize operator -(DoubleSize left, double right) => new(left.Height - right, left.Width - right); 111 | 112 | public static DoubleSize operator *(DoubleSize left, double right) => new(left.Height * right, left.Width * right); 113 | 114 | public static DoubleSize operator /(DoubleSize left, double right) => new(left.Height / right, left.Width / right); 115 | 116 | /// 117 | 118 | public DoubleSize Resize(SizeProperty field, double value) 119 | { 120 | double oldHeight = Height, oldWidth = Width, newHeight = 0, newWidth = 0; 121 | switch (field) 122 | { 123 | case SizeProperty.Height: 124 | newHeight = value; 125 | newWidth = newHeight / (oldHeight / oldWidth); 126 | break; 127 | 128 | case SizeProperty.Width: 129 | newWidth = value; 130 | newHeight = newWidth * (oldHeight / oldWidth); 131 | break; 132 | } 133 | return new DoubleSize(newHeight, newWidth); 134 | } 135 | } -------------------------------------------------------------------------------- /Numerics/MVector2.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MVector2 : Base, IChange, ICloneable, IEquatable> 8 | { 9 | [field: NonSerialized] 10 | public event ChangedEventHandler Changed; 11 | 12 | /// 13 | 14 | public T X { get => Get(); set => Set(value); } 15 | 16 | public T Y { get => Get(); set => Set(value); } 17 | 18 | /// 19 | 20 | public MVector2() : base() { } 21 | 22 | public MVector2(T x, T y) : this() 23 | { 24 | X = x; 25 | Y = y; 26 | } 27 | 28 | /// 29 | 30 | public override void OnPropertyChanged(PropertyEventArgs e) 31 | { 32 | base.OnPropertyChanged(e); 33 | Changed?.Invoke(this); 34 | } 35 | 36 | public override string ToString() => $"{nameof(X)} = {X}, {nameof(Y)} = {Y}"; 37 | 38 | /// 39 | 40 | public MVector2 Clone() => new(X, Y); 41 | object ICloneable.Clone() => Clone(); 42 | 43 | /// 44 | 45 | public static bool operator ==(MVector2 left, MVector2 right) => left.EqualsOverload(right); 46 | 47 | public static bool operator !=(MVector2 left, MVector2 right) => !(left == right); 48 | 49 | public bool Equals(MVector2 i) => this.Equals>(i) && X.Equals(i.X) && Y.Equals(i.Y); 50 | 51 | public override bool Equals(object i) => Equals(i as MVector2); 52 | 53 | public override int GetHashCode() => new { X, Y }.GetHashCode(); 54 | } -------------------------------------------------------------------------------- /Numerics/MVector3.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MVector3 : Base, IChange, ICloneable, IEquatable> 8 | { 9 | [field: NonSerialized] 10 | public event ChangedEventHandler Changed; 11 | 12 | /// 13 | 14 | public T X { get => Get(); set => Set(value); } 15 | 16 | public T Y { get => Get(); set => Set(value); } 17 | 18 | public T Z { get => Get(); set => Set(value); } 19 | 20 | /// 21 | 22 | public MVector3() : base() { } 23 | 24 | public MVector3(T x, T y, T z) : this() 25 | { 26 | X = x; 27 | Y = y; 28 | Z = z; 29 | } 30 | 31 | /// 32 | 33 | public override void OnPropertyChanged(PropertyEventArgs e) 34 | { 35 | base.OnPropertyChanged(e); 36 | Changed?.Invoke(this); 37 | } 38 | 39 | public override string ToString() => $"{nameof(X)} = {X}, {nameof(Y)} = {Y}, {nameof(Z)} = {Z}"; 40 | 41 | /// 42 | 43 | public MVector3 Clone() => new(X, Y, Z); 44 | object ICloneable.Clone() => Clone(); 45 | 46 | /// 47 | 48 | public static bool operator ==(MVector3 left, MVector3 right) => left.EqualsOverload(right); 49 | 50 | public static bool operator !=(MVector3 left, MVector3 right) => !(left == right); 51 | 52 | public bool Equals(MVector3 i) => this.Equals>(i) && X.Equals(i.X) && Y.Equals(i.Y) && Z.Equals(i.Z); 53 | 54 | public override bool Equals(object i) => Equals(i as MVector3); 55 | 56 | public override int GetHashCode() => new { X, Y, Z }.GetHashCode(); 57 | } -------------------------------------------------------------------------------- /Numerics/MVector4.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class MVector4 : Base, IChange, ICloneable, IEquatable> 8 | { 9 | [field: NonSerialized] 10 | public event ChangedEventHandler Changed; 11 | 12 | /// 13 | 14 | public T X { get => Get(); set => Set(value); } 15 | 16 | public T Y { get => Get(); set => Set(value); } 17 | 18 | public T Z { get => Get(); set => Set(value); } 19 | 20 | public T W { get => Get(); set => Set(value); } 21 | 22 | /// 23 | 24 | public MVector4() : base() { } 25 | 26 | public MVector4(T x, T y, T z, T w) : this() 27 | { 28 | X = x; 29 | Y = y; 30 | Z = z; 31 | W = w; 32 | } 33 | 34 | /// 35 | 36 | public override void OnPropertyChanged(PropertyEventArgs e) 37 | { 38 | base.OnPropertyChanged(e); 39 | Changed?.Invoke(this); 40 | } 41 | 42 | public override string ToString() => $"{nameof(X)} = {X}, {nameof(Y)} = {Y}, {nameof(Z)} = {Z}, {nameof(W)} = {W}"; 43 | 44 | /// 45 | 46 | public MVector4 Clone() => new(X, Y, Z, W); 47 | object ICloneable.Clone() => Clone(); 48 | 49 | /// 50 | 51 | public static bool operator ==(MVector4 left, MVector4 right) => left.EqualsOverload(right); 52 | 53 | public static bool operator !=(MVector4 left, MVector4 right) => !(left == right); 54 | 55 | public bool Equals(MVector4 i) => this.Equals>(i) && X.Equals(i.X) && Y.Equals(i.Y) && Z.Equals(i.Z) && W.Equals(i.W); 56 | 57 | public override bool Equals(object i) => Equals(i as MVector4); 58 | 59 | public override int GetHashCode() => new { X, Y, Z, W }.GetHashCode(); 60 | } -------------------------------------------------------------------------------- /Numerics/Number.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | public static class Number 7 | { 8 | public static string Convert(in int input, NumberStyle style) 9 | { 10 | static string Letter(int index) 11 | { 12 | const int columns = 26; 13 | //ceil(log26(Int32.Max)) 14 | const int digitMaximum = 7; 15 | 16 | const string digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 17 | 18 | if (index <= 0) 19 | throw new IndexOutOfRangeException("index must be a positive number"); 20 | 21 | if (index <= columns) 22 | return digits[index - 1].ToString(); 23 | 24 | var result = new StringBuilder().Append(' ', digitMaximum); 25 | 26 | var current = index; 27 | var offset = digitMaximum; 28 | while (current > 0) 29 | { 30 | result[--offset] = digits[--current % columns]; 31 | current /= columns; 32 | } 33 | 34 | return result.ToString(offset, digitMaximum - offset); 35 | } 36 | 37 | static string Ordinal(int input) 38 | { 39 | var result = string.Empty; 40 | switch (input) 41 | { 42 | case 1: 43 | result = "st"; 44 | break; 45 | case 2: 46 | result = "nd"; 47 | break; 48 | case 3: 49 | result = "rd"; 50 | break; 51 | default: 52 | result = "th"; 53 | break; 54 | } 55 | return $"{input}{result}"; 56 | } 57 | 58 | static string Roman(int index) 59 | { 60 | if ((index < 0) || (index > 3999)) 61 | throw new ArgumentOutOfRangeException("insert value betwheen 1 and 3999"); 62 | 63 | if (index < 1) 64 | return string.Empty; 65 | 66 | if (index >= 1000) 67 | return "M" + Roman(index - 1000); 68 | 69 | if (index >= 900) 70 | return "CM" + Roman(index - 900); 71 | 72 | if (index >= 500) 73 | return "D" + Roman(index - 500); 74 | 75 | if (index >= 400) 76 | return "CD" + Roman(index - 400); 77 | 78 | if (index >= 100) 79 | return "C" + Roman(index - 100); 80 | 81 | if (index >= 90) 82 | return "XC" + Roman(index - 90); 83 | 84 | if (index >= 50) 85 | return "L" + Roman(index - 50); 86 | 87 | if (index >= 40) 88 | return "XL" + Roman(index - 40); 89 | 90 | if (index >= 10) 91 | return "X" + Roman(index - 10); 92 | 93 | if (index >= 9) 94 | return "IX" + Roman(index - 9); 95 | 96 | if (index >= 5) 97 | return "V" + Roman(index - 5); 98 | 99 | if (index >= 4) 100 | return "IV" + Roman(index - 4); 101 | 102 | if (index >= 1) 103 | return "I" + Roman(index - 1); 104 | 105 | throw new ArgumentOutOfRangeException(); 106 | } 107 | 108 | switch (style) 109 | { 110 | case NumberStyle.Letter: return Letter(input); 111 | case NumberStyle.Ordinal: return Ordinal(input); 112 | case NumberStyle.Roman: return Roman(input); 113 | } 114 | return default; 115 | } 116 | } -------------------------------------------------------------------------------- /Numerics/NumberFormat.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | public static class NumberFormat 4 | { 5 | public const string Default = "N0"; 6 | 7 | public const string Percent = "P0"; 8 | } -------------------------------------------------------------------------------- /Numerics/NumberOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies a number operation. 6 | [Serializable] 7 | public enum NumberOperation 8 | { 9 | /// Addition operation (+). 10 | Add, 11 | /// Division operation (/). 12 | Divide, 13 | /// Multiplication operation (*). 14 | Multiply, 15 | /// Subtraction operation (-). 16 | Subtract 17 | } -------------------------------------------------------------------------------- /Numerics/NumberStyle.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | public enum NumberStyle 4 | { 5 | Letter, 6 | Ordinal, 7 | Roman 8 | } -------------------------------------------------------------------------------- /Numerics/One.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static Imagin.Core.Numerics.M; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | /// 7 | /// Specifies a number in the range of [0, 1] (input is truncated if outside of range). 8 | /// 9 | [Serializable] 10 | public struct One 11 | { 12 | public static One Zero => 0; 13 | 14 | public readonly double Value; 15 | 16 | /// 17 | 18 | public One(double value) => Value = Clamp(value, 1); 19 | 20 | /// 21 | 22 | public static implicit operator One(double input) => new(input); 23 | 24 | public static implicit operator double(One input) => input.Value; 25 | 26 | /// 27 | 28 | public static bool operator <(One a, One b) => a.Value < b.Value; 29 | 30 | public static bool operator >(One a, One b) => a.Value > b.Value; 31 | 32 | /// 33 | 34 | public static bool operator ==(One a, One b) => a.Value == b.Value; 35 | 36 | public static bool operator !=(One a, One b) => a.Value != b.Value; 37 | 38 | public static bool operator <=(One a, One b) => a.Value <= b.Value; 39 | 40 | public static bool operator >=(One a, One b) => a.Value >= b.Value; 41 | 42 | /// 43 | 44 | public static double operator +(One a, One b) => a.Value + b.Value; 45 | 46 | public static double operator -(One a, One b) => a.Value - b.Value; 47 | 48 | public static double operator /(One a, One b) => a.Value / b.Value; 49 | 50 | public static double operator *(One a, One b) => a.Value * b.Value; 51 | 52 | /// 53 | 54 | public static double operator +(One a, double b) => a.Value + b; 55 | 56 | public static double operator -(One a, double b) => a.Value - b; 57 | 58 | public static double operator /(One a, double b) => a.Value / b; 59 | 60 | public static double operator *(One a, double b) => a.Value * b; 61 | 62 | /// 63 | 64 | public override bool Equals(object i) => i is One one ? this == one : (i is double || i is float || i is int) && this == new One(System.Convert.ToDouble(i)); 65 | 66 | public override int GetHashCode() => Value.GetHashCode(); 67 | 68 | /// 69 | 70 | public static One Parse(string input) => double.Parse(input); 71 | 72 | public static bool TryParse(string input, out One result) 73 | { 74 | var r = double.TryParse(input, out double d); 75 | result = d; 76 | return r; 77 | } 78 | 79 | /// 80 | 81 | public string ToString(string format) => Value.ToString(format); 82 | 83 | public override string ToString() => Value.ToString(); 84 | } -------------------------------------------------------------------------------- /Numerics/Operators.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Numerics; 2 | 3 | public enum Operators { Equal, NotEqual, Greater, Lesser, GreaterOrEqual, LesserOrEqual } -------------------------------------------------------------------------------- /Numerics/Point2.Generic.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class Point2 : Base, ICloneable, IEquatable> 8 | { 9 | public T X { get => Get(); set => Set(value); } 10 | 11 | public T Y { get => Get(); set => Set(value); } 12 | 13 | public Point2() : base() { } 14 | 15 | public Point2(T x, T y) : this() 16 | { 17 | X = x; Y = y; 18 | } 19 | 20 | public Point2 Clone() => new(X, Y); 21 | object ICloneable.Clone() => Clone(); 22 | 23 | public override string ToString() => $"X => {X}, Y => {Y}"; 24 | 25 | #region == 26 | 27 | public static bool operator ==(Point2 left, Point2 right) => left.EqualsOverload(right); 28 | 29 | public static bool operator !=(Point2 left, Point2 right) => !(left == right); 30 | 31 | public override bool Equals(object i) => i is Point2 j && Equals(j); 32 | 33 | public bool Equals(Point2 right) => this.Equals>(right) && X?.Equals(right.X) == true && Y?.Equals(right.Y) == true; 34 | 35 | public override int GetHashCode() => XArray.New(X, Y).GetHashCode(); 36 | 37 | #endregion 38 | } -------------------------------------------------------------------------------- /Numerics/Point2.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public class Point2 : Base, ICloneable, IEquatable 8 | { 9 | public double X { get => Get(.0); set => Set(value); } 10 | 11 | public double Y { get => Get(.0); set => Set(value); } 12 | 13 | public Point2() : base() { } 14 | 15 | public Point2(double x, double y) : this() 16 | { 17 | X = x; Y = y; 18 | } 19 | 20 | public Point2 Clone() => new(X, Y); 21 | object ICloneable.Clone() => Clone(); 22 | 23 | public override string ToString() => $"X => {X}, Y => {Y}"; 24 | 25 | #region == 26 | 27 | public static bool operator ==(Point2 left, Point2 right) => left.EqualsOverload(right); 28 | 29 | public static bool operator !=(Point2 left, Point2 right) => !(left == right); 30 | 31 | public override bool Equals(object i) => Equals(i as Point2); 32 | 33 | public bool Equals(Point2 right) => this.Equals(right) && X == right.X && Y == right.Y; 34 | 35 | public override int GetHashCode() => XArray.New(X, Y).GetHashCode(); 36 | 37 | #endregion 38 | } -------------------------------------------------------------------------------- /Numerics/Quadrants.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | [Serializable] 6 | public enum Quadrants 7 | { 8 | /// [🞧, 🞧] 9 | I, 10 | /// [🞧, ⚊] 11 | II, 12 | /// [⚊, ⚊] 13 | III, 14 | /// [⚊, 🞧] 15 | IV 16 | } -------------------------------------------------------------------------------- /Numerics/Random.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace Imagin.Core.Numerics; 6 | 7 | public static class Random 8 | { 9 | public static readonly System.Random Current = new(); 10 | 11 | public static bool NextBoolean() 12 | => NextInt32(0, 2) == 1; 13 | 14 | public static bool NextBoolean(double probability) 15 | => NextDouble() < probability / 100.0; 16 | 17 | public static byte NextByte() 18 | => NextInt32(0, 256).Byte(); 19 | 20 | public static double NextDouble() 21 | => Current.NextDouble(); 22 | 23 | public static float NextSingle() 24 | => Current.NextDouble().Single(); 25 | 26 | public static float NextSingle(float range) 27 | => (Current.NextDouble() * range).Single(); 28 | 29 | public static float NextSingle(float min, float max) 30 | => ((Current.NextDouble() * (max - min)) + min).Single(); 31 | 32 | public static int NextInt32(int min, int max) 33 | => Current.Next(min, max); 34 | 35 | public static int NextInt32(IEnumerable values) 36 | => NextInt32(values.ToArray()); 37 | 38 | public static int NextInt32(params int[] values) 39 | => values[NextInt32(0, values.Length)]; 40 | 41 | public static ushort NextUInt16(ushort minimum, ushort maximum) 42 | => Current.Next(minimum.Int32(), maximum.Int32()).UInt16(); 43 | 44 | public static uint NextUInt32(uint minimum, uint maximum) 45 | => Current.Next(minimum.Int32(), maximum.Int32()).UInt32(); 46 | 47 | public static ulong NextUInt64(ulong minimum, ulong maximum) 48 | => Current.Next(minimum.Int32(), maximum.Int32()).UInt64(); 49 | 50 | public static string String(string AllowedCharacters, int MinLength, int MaxLength) 51 | { 52 | char[] characters = new char[MaxLength]; 53 | int setLength = AllowedCharacters.Length; 54 | 55 | int length = Current.Next(MinLength, MaxLength + 1); 56 | for (int i = 0; i < length; ++i) 57 | characters[i] = AllowedCharacters[Current.Next(setLength)]; 58 | 59 | return new string(characters, 0, length); 60 | } 61 | } -------------------------------------------------------------------------------- /Numerics/Range.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core; 5 | 6 | [Serializable] 7 | public struct Range : IEquatable>, IRange 8 | { 9 | public static Range Default = new(default, default); 10 | 11 | /// 12 | 13 | public readonly T Minimum; 14 | T IRange.Minimum => Minimum; 15 | 16 | public readonly T Maximum; 17 | T IRange.Maximum => Minimum; 18 | 19 | /// 20 | 21 | public Range(T minimum, T maximum) 22 | { 23 | Minimum = minimum; 24 | Maximum = maximum; 25 | } 26 | 27 | public override string ToString() => $"{nameof(Minimum)} = {Minimum}, {nameof(Maximum)} = {Maximum}"; 28 | 29 | /// 30 | 31 | public static bool operator ==(Range left, Range right) => left.EqualsOverload(right); 32 | 33 | public static bool operator !=(Range left, Range right) => !(left == right); 34 | 35 | public bool Equals(Range i) => this.Equals>(i) && Minimum.Equals(i.Minimum) && Maximum.Equals(i.Maximum); 36 | 37 | public override bool Equals(object i) => i is Range j ? Equals(j) : false; 38 | 39 | public override int GetHashCode() => new { Minimum, Maximum }.GetHashCode(); 40 | } -------------------------------------------------------------------------------- /Numerics/RangeFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies the format of a range. 6 | [Serializable] 7 | public enum RangeFormat 8 | { 9 | /// Specifies a range of [0, 1]. 10 | Nominal, 11 | /// Specifies a standard range. 12 | Standard, 13 | /// Specifies a zero-based range. 14 | ZeroBased, 15 | } -------------------------------------------------------------------------------- /Numerics/Shapes2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imagin.Core.Reflection; 3 | 4 | namespace Imagin.Core.Numerics; 5 | 6 | [Serializable] 7 | public enum Shapes2 8 | { 9 | [Image("Square.png", AssemblyType.Core)] Square, 10 | [Image("Circle.png", AssemblyType.Core)] Circle 11 | } -------------------------------------------------------------------------------- /Numerics/Shapes3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | [Serializable] 6 | public enum Shapes3 7 | { 8 | Cube, 9 | Sphere 10 | } -------------------------------------------------------------------------------- /Numerics/SizeProperty.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies a property of size. 6 | [Serializable] 7 | public enum SizeProperty { Height, Width } -------------------------------------------------------------------------------- /Numerics/UDouble.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | using System; 3 | 4 | namespace Imagin.Core; 5 | 6 | /// Represents an unsigned double-precision floating-point number. 7 | [Serializable] 8 | public struct UDouble 9 | { 10 | /// 11 | /// Equivalent to . 12 | /// 13 | public readonly static UDouble Epsilon = double.Epsilon; 14 | 15 | /// 16 | /// Represents the largest possible value of (equivalent to ). 17 | /// 18 | public readonly static UDouble MaxValue = double.MaxValue; 19 | 20 | /// 21 | /// Represents the smallest possible value of (0). 22 | /// 23 | public readonly static UDouble MinValue = 0; 24 | 25 | /// 26 | /// Equivalent to . 27 | /// 28 | public readonly static UDouble NaN = double.NaN; 29 | 30 | /// 31 | /// Equivalent to . 32 | /// 33 | public readonly static UDouble PositiveInfinity = double.PositiveInfinity; 34 | readonly double value; 35 | 36 | /// 37 | /// Initializes an instance of the structure. 38 | /// 39 | /// 40 | public UDouble(double input) 41 | { 42 | if (double.IsNegativeInfinity(input)) 43 | throw new NotSupportedException(); 44 | 45 | value = M.Clamp(input, double.MaxValue); 46 | } 47 | 48 | public static implicit operator double(UDouble d) => d.value; 49 | 50 | public static implicit operator UDouble(double d) => new(d); 51 | 52 | public static bool operator <(UDouble a, UDouble b) => a.value < b.value; 53 | 54 | public static bool operator >(UDouble a, UDouble b) => a.value > b.value; 55 | 56 | public static bool operator ==(UDouble a, UDouble b) => a.value == b.value; 57 | 58 | public static bool operator !=(UDouble a, UDouble b) => a.value != b.value; 59 | 60 | public static bool operator <=(UDouble a, UDouble b) => a.value <= b.value; 61 | 62 | public static bool operator >=(UDouble a, UDouble b) => a.value >= b.value; 63 | 64 | public static UDouble operator +(UDouble a, UDouble b) => a.value + b.value; 65 | 66 | public static UDouble operator -(UDouble a, UDouble b) => a.value - b.value; 67 | 68 | public static UDouble operator /(UDouble a, UDouble b) => a.value / b.value; 69 | 70 | public static UDouble operator *(UDouble a, UDouble b) => a.value * b.value; 71 | 72 | public UDouble Clamp(UDouble maximum, UDouble minimum = default) => value > maximum ? maximum : (value < minimum ? minimum : value); 73 | 74 | public override bool Equals(object a) => a is UDouble b ? this == b : false; 75 | 76 | public override int GetHashCode() => value.GetHashCode(); 77 | 78 | public static UDouble Parse(string input) => double.Parse(input); 79 | 80 | public static bool TryParse(string input, out UDouble result) 81 | { 82 | var r = double.TryParse(input, out double d); 83 | result = d; 84 | return r; 85 | } 86 | 87 | public string ToString(string format) => value.ToString(format); 88 | 89 | public override string ToString() => value.ToString(); 90 | } -------------------------------------------------------------------------------- /Numerics/USingle.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Numerics; 2 | using System; 3 | 4 | namespace Imagin.Core; 5 | 6 | /// Represents an unsigned single-precision floating-point number. 7 | [Serializable] 8 | public struct USingle 9 | { 10 | /// 11 | /// Equivalent to . 12 | /// 13 | public readonly static USingle Epsilon = float.Epsilon; 14 | 15 | /// 16 | /// Represents the largest possible value of (equivalent to ). 17 | /// 18 | public readonly static USingle MaxValue = float.MaxValue; 19 | 20 | /// 21 | /// Represents the smallest possible value of (0). 22 | /// 23 | public readonly static USingle MinValue = 0; 24 | 25 | /// 26 | /// Equivalent to . 27 | /// 28 | public readonly static USingle NaN = float.NaN; 29 | 30 | /// 31 | /// Equivalent to . 32 | /// 33 | public readonly static USingle PositiveInfinity = float.PositiveInfinity; 34 | readonly float value; 35 | 36 | /// 37 | /// Initializes an instance of the structure. 38 | /// 39 | /// 40 | public USingle(float input) 41 | { 42 | if (float.IsNegativeInfinity(input)) 43 | throw new NotSupportedException(); 44 | 45 | value = M.Clamp(input, float.MaxValue); 46 | } 47 | 48 | public static implicit operator float(USingle d) => d.value; 49 | 50 | public static implicit operator USingle(float d) => new(d); 51 | 52 | public static bool operator <(USingle a, USingle b) => a.value < b.value; 53 | 54 | public static bool operator >(USingle a, USingle b) => a.value > b.value; 55 | 56 | public static bool operator ==(USingle a, USingle b) => a.value == b.value; 57 | 58 | public static bool operator !=(USingle a, USingle b) => a.value != b.value; 59 | 60 | public static bool operator <=(USingle a, USingle b) => a.value <= b.value; 61 | 62 | public static bool operator >=(USingle a, USingle b) => a.value >= b.value; 63 | 64 | public static USingle operator +(USingle a, USingle b) => a.value + b.value; 65 | 66 | public static USingle operator -(USingle a, USingle b) => a.value - b.value; 67 | 68 | public static USingle operator /(USingle a, USingle b) => a.value / b.value; 69 | 70 | public static USingle operator *(USingle a, USingle b) => a.value * b.value; 71 | 72 | public USingle Clamp(USingle maximum, USingle minimum = default) => value > maximum ? maximum : (value < minimum ? minimum : value); 73 | 74 | public override bool Equals(object a) => a is USingle b ? this == b : false; 75 | 76 | public override int GetHashCode() => value.GetHashCode(); 77 | 78 | public static USingle Parse(string input) => float.Parse(input); 79 | 80 | public static bool TryParse(string input, out USingle result) 81 | { 82 | var r = float.TryParse(input, out float d); 83 | result = d; 84 | return r; 85 | } 86 | 87 | public string ToString(string format) => value.ToString(format); 88 | 89 | public override string ToString() => value.ToString(); 90 | } -------------------------------------------------------------------------------- /Numerics/Unit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Numerics; 4 | 5 | /// Specifies a unit of measurement. 6 | [Serializable] 7 | public enum Unit 8 | { 9 | /// Specifies a device pixel as the unit of measure. 10 | [Abbreviation("px")] 11 | Pixel, 12 | /// Specifies an inch as the unit of measure. 13 | [Abbreviation("in")] 14 | Inch, 15 | /// Specifies a centimeter (1/2.54 inch) as the unit of measure. 16 | [Abbreviation("cm")] 17 | Centimeter, 18 | /// Specifies a millimeter (1/25.4 inch) as the unit of measure. 19 | [Abbreviation("mm")] 20 | Millimeter, 21 | /// Specifies a printer's point (1/72 inch) as the unit of measure. 22 | [Abbreviation("pt")] 23 | Point, 24 | /// Specifies a pica (1/6 inch) as the unit of measure. 25 | [Abbreviation("pc")] 26 | Pica, 27 | /// Specifies a twip (1/1140 inch) as the unit of measure. 28 | [Abbreviation("tw")] 29 | Twip, 30 | /// Specifies a character (1/12 inch) as the unit of measure. 31 | [Abbreviation("ch")] 32 | Character, 33 | /// Specifies an en (1/144.54 inch) as the unit of measure. 34 | [Abbreviation("en")] 35 | En 36 | } -------------------------------------------------------------------------------- /Numerics/Vector.Byte.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using Imagin.Core.Reflection; 3 | using System; 4 | using System.Globalization; 5 | 6 | namespace Imagin.Core.Numerics; 7 | 8 | [Image(AssemblyType.Core, "Color.png"), Name("Color"), Serializable] 9 | public struct ByteVector4 : IEquatable 10 | { 11 | public const uint Length = 4; 12 | 13 | readonly Guid id = Guid.NewGuid(); 14 | 15 | #region Properties 16 | 17 | public static ByteVector4 Black => new(0, 0, 0, 255); 18 | 19 | public static ByteVector4 White => new(255); 20 | 21 | public static ByteVector4 Transparent => new(0); 22 | 23 | /// 24 | 25 | public byte X { get; private set; } 26 | 27 | public byte Y { get; private set; } 28 | 29 | public byte Z { get; private set; } 30 | 31 | public byte W { get; private set; } 32 | 33 | [Hide] 34 | public Vector3 XYZ => new(X, Y, Z); 35 | 36 | /// (0) = 37 | [Hide] 38 | public byte R => X; 39 | 40 | /// (1) = 41 | [Hide] 42 | public byte G => Y; 43 | 44 | /// (2) = 45 | [Hide] 46 | public byte B => Z; 47 | 48 | /// (3) = 49 | [Hide] 50 | public byte A => W; 51 | 52 | public byte this[int index] => new byte[] { X, Y, Z, W }[index]; 53 | 54 | #endregion 55 | 56 | #region ByteVector4 57 | 58 | public ByteVector4() : this(0) { } 59 | 60 | public ByteVector4(byte xyzw) : this(xyzw, xyzw, xyzw, xyzw) { } 61 | 62 | public ByteVector4(byte x, byte y, byte z, byte w) 63 | { 64 | X = x; Y = y; Z = z; W = w; 65 | } 66 | 67 | public ByteVector4(string hexadecimal) : this(0) 68 | { 69 | if (hexadecimal.Length > 8) 70 | throw new ArgumentOutOfRangeException(nameof(hexadecimal)); 71 | 72 | switch (hexadecimal.Length) 73 | { 74 | case 3: 75 | hexadecimal = "{0}{1}{2}{3}".F("FF", new string(hexadecimal[0], 2), new string(hexadecimal[1], 2), new string(hexadecimal[2], 2)); 76 | break; 77 | case 6: 78 | hexadecimal = "{0}{1}".F("FF", hexadecimal); 79 | break; 80 | default: 81 | hexadecimal = string.Concat(hexadecimal, new string('0', 8 - hexadecimal.Length)); 82 | break; 83 | } 84 | 85 | X = Parse(hexadecimal.Substring(2, 2)); 86 | Y = Parse(hexadecimal.Substring(4, 2)); 87 | Z = Parse(hexadecimal.Substring(6, 2)); 88 | W = Parse(hexadecimal.Substring(0, 2)); 89 | } 90 | 91 | /// 92 | 93 | public static implicit operator byte[](ByteVector4 input) 94 | => XArray.New(input.X, input.Y, input.Z, input.W); 95 | 96 | public static implicit operator string(ByteVector4 input) => input.ToString(); 97 | 98 | #endregion 99 | 100 | #region Methods 101 | 102 | public override string ToString() 103 | => A.ToString("X2") + R.ToString("X2") + G.ToString("X2") + B.ToString("X2"); 104 | 105 | public string ToString(bool alpha) 106 | => alpha ? ToString() : R.ToString("X2") + G.ToString("X2") + B.ToString("X2"); 107 | 108 | public string ToShortString() 109 | { 110 | var result = ToString(false); 111 | if (result?.Length == 6) 112 | { 113 | if (result[0] == result[1] && result[2] == result[3] && result[4] == result[5]) 114 | return $"{result[0]}{result[2]}{result[4]}"; 115 | } 116 | return result; 117 | } 118 | 119 | /// 120 | 121 | public static byte Parse(string input) => int.Parse(input, NumberStyles.HexNumber).Byte(); 122 | 123 | #endregion 124 | 125 | #region == 126 | 127 | public static bool operator ==(ByteVector4 a, ByteVector4 b) 128 | => a.EqualsOverload(b); 129 | 130 | public static bool operator !=(ByteVector4 a, ByteVector4 b) 131 | => !(a == b); 132 | 133 | public bool Equals(ByteVector4 i) 134 | => this.Equals(i) && X.Equals(i.X) && Y.Equals(i.Y) && Z.Equals(i.Z) && W.Equals(i.W); 135 | 136 | public override bool Equals(object i) 137 | => i is ByteVector4 j && Equals(j); 138 | 139 | public override int GetHashCode() 140 | => id.GetHashCode(); 141 | 142 | #endregion 143 | } -------------------------------------------------------------------------------- /Numerics/VectorType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | /// 6 | /// Specifies a type of ( corresponds to ∈ [m, 1]; corresponds to ∈ [1, n]). 7 | /// 8 | [Serializable] 9 | public enum VectorType 10 | { 11 | /// Corresponds to ∈ [m, 1]. 12 | Column, 13 | /// Corresponds to ∈ [1, n]. 14 | Row 15 | } -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Resources; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Imagin.Common")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Imagin")] 12 | [assembly: AssemblyProduct("Imagin.Common")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | [assembly: NeutralResourcesLanguage("en")] 17 | 18 | //[assembly: CLSCompliant(true)] 19 | 20 | // Version information for an assembly consists of the following four values: 21 | // 22 | // Major Version 23 | // Minor Version 24 | // Build Number 25 | // Revision 26 | // 27 | // You can specify all the values or you can default the Build and Revision Numbers 28 | // by using the '*' as shown below: 29 | // [assembly: AssemblyVersion("1.0.*")] 30 | [assembly: AssemblyVersion("0.0.0.0")] 31 | [assembly: AssemblyFileVersion("0.0.0.0")] 32 | -------------------------------------------------------------------------------- /Reflection/AssemblyContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Xml.Serialization; 4 | 5 | namespace Imagin.Core.Reflection; 6 | 7 | /// Defines facilities for managing an . 8 | [Serializable] 9 | public class AssemblyContext 10 | { 11 | /// A reference to the . 12 | [XmlIgnore] 13 | public AppDomain AppDomain { get; set; } = null; 14 | 15 | /// 16 | /// A reference to an . 17 | /// 18 | [XmlIgnore] 19 | public Assembly Assembly { get; set; } = null; 20 | 21 | /// A unique identifier. 22 | public Guid Id { get; set; } = default; 23 | 24 | AssemblyContext() { } 25 | 26 | /// 27 | /// Initializes a new instance of the class. 28 | /// 29 | /// 30 | /// 31 | public AssemblyContext(Guid id, Assembly assembly, AppDomain appDomain) 32 | { 33 | Id = id; 34 | Assembly = assembly; 35 | AppDomain = appDomain; 36 | } 37 | } -------------------------------------------------------------------------------- /Reflection/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Imagin.Core.Reflection; 7 | 8 | public class AssemblyInfo 9 | { 10 | public readonly Assembly Assembly; 11 | 12 | /// 13 | 14 | public readonly string Company; 15 | 16 | public readonly string Copyright; 17 | 18 | public readonly string Description; 19 | 20 | /// 21 | 22 | public readonly string FileVersion; 23 | 24 | public readonly string Version; 25 | 26 | /// 27 | 28 | public readonly string Name; 29 | 30 | public readonly string Product; 31 | 32 | public readonly string Title; 33 | 34 | /// 35 | 36 | public AssemblyInfo(string assemblyName) : base() 37 | { 38 | Assembly = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(assembly => assembly.GetName().Name == assemblyName); 39 | 40 | /// 41 | 42 | Company 43 | = GetAttribute()?.Company; 44 | Copyright 45 | = GetAttribute()?.Copyright; 46 | Description 47 | = GetAttribute()?.Description; 48 | FileVersion 49 | = GetAttribute()?.Version; 50 | Name 51 | = Assembly.GetName().Name; 52 | Product 53 | = GetAttribute()?.Product; 54 | Title 55 | = GetAttribute()?.Title; 56 | Version 57 | = GetAttribute()?.Version; 58 | } 59 | 60 | /// 61 | 62 | T GetAttribute() where T : Attribute => Assembly.GetCustomAttributes(typeof(T)).OfType().FirstOrDefault(); 63 | } -------------------------------------------------------------------------------- /Reflection/AssemblySource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Reflection; 4 | 5 | public enum AssemblySource 6 | { 7 | /// The assembly of the method that invoked the currently executing method. 8 | Calling, 9 | /// The process executable in the default application domain. In other application domains, this is the first executable that was executed by . 10 | Entry, 11 | /// The assembly that contains the code that is currently executing. 12 | Executing, 13 | } -------------------------------------------------------------------------------- /Reflection/AssemblyType.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Reflection; 2 | 3 | public enum AssemblyType { Color, Core, Current, Shared, Unspecified } -------------------------------------------------------------------------------- /Reflection/ICloneHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Reflection; 2 | 3 | public interface ICloneHandler 4 | { 5 | object Clone(object input); 6 | } -------------------------------------------------------------------------------- /Reflection/MemberView.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Reflection; 2 | 3 | public enum MemberView { All, Single, Tab } -------------------------------------------------------------------------------- /Serialization/BinarySerializer.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | using System; 3 | using System.IO; 4 | using System.Runtime.Serialization.Formatters.Binary; 5 | 6 | namespace Imagin.Core.Serialization; 7 | 8 | public class BinarySerializer 9 | { 10 | public static Result Deserialize(string filePath, out T data) 11 | { 12 | Result result = null; 13 | data = default; 14 | 15 | var stream = default(FileStream); 16 | try 17 | { 18 | if (File.Exists(filePath)) 19 | { 20 | stream = new FileStream(filePath, FileMode.Open); 21 | data = (T)new BinaryFormatter().Deserialize(stream); 22 | result = new Success(); 23 | } 24 | } 25 | catch (Exception e) 26 | { 27 | result = (Error)new DeserializationFailedException(data?.GetType() ?? typeof(object), e); 28 | Log.Write(result); 29 | } 30 | finally 31 | { 32 | stream?.Close(); 33 | } 34 | return result; 35 | } 36 | 37 | public static Result Serialize(string filePath, object data) 38 | { 39 | Result result = null; 40 | 41 | var type = data.GetType(); 42 | var fileStream = default(FileStream); 43 | 44 | try 45 | { 46 | var directoryPath = Path.GetDirectoryName(filePath); 47 | if (!Directory.Exists(directoryPath)) 48 | Directory.CreateDirectory(directoryPath); 49 | 50 | fileStream = new FileStream(filePath, FileMode.Create); 51 | 52 | var binaryFormatter = new BinaryFormatter(); 53 | binaryFormatter.Serialize(fileStream, data); 54 | result = new Success(); 55 | } 56 | catch (Exception e) 57 | { 58 | result = (Error)new SerializationFailedException(data?.GetType() ?? typeof(object), e); 59 | Log.Write(result); 60 | } 61 | finally 62 | { 63 | fileStream?.Close(); 64 | } 65 | return result; 66 | } 67 | } -------------------------------------------------------------------------------- /Serialization/ISerialize.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Analytics; 2 | 3 | namespace Imagin.Core.Serialization; 4 | 5 | public interface ISerialize 6 | { 7 | string FilePath { get; } 8 | 9 | Result Deserialize(string filePath, out object data); 10 | 11 | Result Serialize(object data); 12 | 13 | Result Serialize(string filePath, object data); 14 | } -------------------------------------------------------------------------------- /Serialization/SerializationType.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core; 2 | 3 | public enum SerializationType { Binary, Image, Text, Xml } -------------------------------------------------------------------------------- /Storage/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Storage; 5 | 6 | /// Specifies a semi-colon (;) separated list of file or folder extensions. 7 | public struct Extensions 8 | { 9 | public static Extensions Empty = new(string.Empty); 10 | 11 | public int Count => values.Length; 12 | 13 | readonly string value; 14 | 15 | readonly string[] values; 16 | public string[] Values => values; 17 | 18 | /// Initializes an instance of the structure. 19 | public Extensions(string input) 20 | { 21 | value 22 | = input; 23 | values 24 | = input.Split(XArray.New(';'), StringSplitOptions.RemoveEmptyEntries); 25 | } 26 | 27 | /// Initializes an instance of the structure. 28 | public Extensions(string[] input) : this(input.ToString(";")) { } 29 | 30 | public static implicit operator string(Extensions i) => i.value; 31 | 32 | public static implicit operator Extensions(string i) => new(i); 33 | 34 | public static bool operator <(Extensions a, Extensions b) => a.Count < b.Count; 35 | 36 | public static bool operator >(Extensions a, Extensions b) => a.Count > b.Count; 37 | 38 | public static bool operator ==(Extensions a, Extensions b) => a.value == b.value; 39 | 40 | public static bool operator !=(Extensions a, Extensions b) => a.value != b.value; 41 | 42 | public static bool operator <=(Extensions a, Extensions b) => a.Count <= b.Count; 43 | 44 | public static bool operator >=(Extensions a, Extensions b) => a.Count >= b.Count; 45 | 46 | public static Extensions operator +(Extensions a, Extensions b) => $"{a.value};{b.value}"; 47 | 48 | public static Extensions operator +(Extensions a, string b) => $"{a.value};{b}"; 49 | 50 | public override bool Equals(object a) => a is Extensions b ? this == b : false; 51 | 52 | public override int GetHashCode() => value.GetHashCode(); 53 | 54 | public override string ToString() => value; 55 | } -------------------------------------------------------------------------------- /Storage/FileAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core; 4 | 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 6 | public class FileAttribute : Attribute 7 | { 8 | public string Extension { get; set; } 9 | 10 | public string Name { get; set; } 11 | 12 | public FileAttribute(string name = "", string extension = "") 13 | { 14 | Name = name; Extension = extension; 15 | } 16 | } -------------------------------------------------------------------------------- /Storage/FileSize.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | 4 | namespace Imagin.Core.Storage; 5 | 6 | [Serializable] 7 | public struct FileSize : IEquatable 8 | { 9 | /// Specifies the largest possible value (). 10 | public readonly static double MaxValue = ulong.MaxValue; 11 | 12 | /// Specifies the smallest possible value (). 13 | public readonly static double MinValue = ulong.MinValue; 14 | 15 | /// 16 | 17 | public ulong Value { get; private set; } 18 | 19 | /// 20 | 21 | public FileSize(long input) => Value = input.UInt64(); 22 | 23 | public FileSize(ulong input) => Value = input; 24 | 25 | /// 26 | 27 | public static bool operator ==(FileSize a, FileSize b) => a.EqualsOverload(b); 28 | 29 | public static bool operator !=(FileSize a, FileSize b) => !(a == b); 30 | 31 | /// 32 | 33 | public bool Equals(FileSize i) 34 | => this.Equals(i) && Value.Equals(i.Value); 35 | 36 | public override bool Equals(object i) 37 | => Equals((FileSize)i); 38 | 39 | public override int GetHashCode() 40 | => Value.GetHashCode(); 41 | 42 | /// 43 | 44 | public override string ToString() => ToString(FileSizeFormat.BinaryUsingSI, 1); 45 | 46 | public string ToString(FileSizeFormat format, int round = 1) 47 | { 48 | if (format == FileSizeFormat.Bytes) 49 | return Value.ToString(); 50 | 51 | var Labels = new string[] 52 | { 53 | "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" 54 | }; 55 | 56 | if (format == FileSizeFormat.BinaryUsingSI || format == FileSizeFormat.DecimalUsingSI) 57 | { 58 | Labels = new string[] 59 | { 60 | "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" 61 | }; 62 | } 63 | 64 | if (Value == 0) 65 | return "0 B"; 66 | 67 | var f = format == FileSizeFormat.BinaryUsingSI || format == FileSizeFormat.IECBinary ? (ulong)1024 : 1000; 68 | 69 | var m = (int)Math.Log(Value, f); 70 | var a = (decimal)Value / (1L << (m * 10)); 71 | 72 | if (Math.Round(a, round) >= 1000) 73 | { 74 | m += 1; 75 | a /= f; 76 | } 77 | 78 | var result = string.Format("{0:n" + round + "}", a); 79 | 80 | var j = result.Length; 81 | for (var i = result.Length - 1; i >= 0; i--) 82 | { 83 | if (result[i] == '.') 84 | { 85 | j--; 86 | break; 87 | } 88 | if (result[i] == '0') 89 | { 90 | j--; 91 | } 92 | else break; 93 | } 94 | 95 | return $"{result.Substring(0, j)} {Labels[m]}"; ; 96 | } 97 | } -------------------------------------------------------------------------------- /Storage/FileSizeFormat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Storage; 4 | 5 | [Serializable] 6 | public enum FileSizeFormat 7 | { 8 | /// Specifies number of bytes with no base quantity.Total number of bytes. 9 | Bytes = 0, 10 | /// Specifies number of bytes with a base quantity of 1024B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB 11 | IECBinary, 12 | /// Specifies number of bytes with a base quantity of 1000B, kB, MB, GB, TB, PB, EB, ZB, YB 13 | BinaryUsingSI, 14 | /// Specifies number of bytes with a base quantity of 1000B, kB, MB, GB, TB, PB, EB, ZB, YB 15 | DecimalUsingSI 16 | } -------------------------------------------------------------------------------- /Storage/StoragePath.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace Imagin.Core.Storage; 7 | 8 | public class StoragePath 9 | { 10 | public const string Root = @"\"; 11 | 12 | public const string RootName = "This PC"; 13 | 14 | /// 15 | 16 | public static char[] InvalidFileNameCharacters => Path.GetInvalidFileNameChars(); 17 | 18 | /// 19 | 20 | public static string CleanName(string fileName) => Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty)); 21 | 22 | /// 23 | 24 | public const string DefaultCloneFormat = "{0} [{1}]"; 25 | 26 | /// 27 | /// Gets a clone of the given path using the given name format. 28 | /// 29 | public static string Clone(string path, string nameFormat, Predicate exists) 30 | { 31 | var parent = Path.GetDirectoryName(path); 32 | 33 | var extension = Path.GetExtension(path); 34 | var name = Path.GetFileNameWithoutExtension(path); 35 | 36 | var n = name; 37 | string result() => $@"{parent}\{n}{extension}".Replace(@"\\", @"\"); 38 | 39 | var i = 0; 40 | while (exists(result())) 41 | { 42 | n = nameFormat.F(name, i); 43 | i++; 44 | } 45 | 46 | return result(); 47 | } 48 | 49 | /// 50 | /// 51 | /// Enumerates the given starting with the last ; gets everything after first period, if one is found. 52 | /// 53 | /// 54 | /// 55 | public static string GetLastExtension(string path) 56 | { 57 | if (path.NullOrEmpty()) 58 | return null; 59 | 60 | var f = string.Empty; 61 | for (var i = path.Length - 1; i >= 0; i--) 62 | { 63 | if (path[i] == '.') 64 | return f.Empty() ? null : f; 65 | 66 | f = $"{path[i]}{f}"; 67 | } 68 | return null; 69 | } 70 | } -------------------------------------------------------------------------------- /Text/Bullets.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Text; 4 | 5 | [Serializable] 6 | public enum Bullets 7 | { 8 | [Abbreviation("■")] 9 | Square, 10 | [Abbreviation("□")] 11 | SquareOutline, 12 | [Abbreviation("●")] 13 | Circle, 14 | [Abbreviation("○")] 15 | CircleOutline, 16 | [Abbreviation("◆")] 17 | Diamond, 18 | [Abbreviation("◇")] 19 | DiamondOutline, 20 | /// 21 | /// A., B., C. 22 | /// 23 | LetterUpperPeriod, 24 | /// 25 | /// A), B), C) 26 | /// 27 | LetterUpperParenthesis, 28 | /// 29 | /// a., b., c. 30 | /// 31 | LetterLowerPeriod, 32 | /// 33 | /// a), b), c) 34 | /// 35 | LetterLowerParenthesis, 36 | /// 37 | /// 1., 2., 3. 38 | /// 39 | NumberPeriod, 40 | /// 41 | /// 1), 2), 3) 42 | /// 43 | NumberParenthesis, 44 | /// 45 | /// I., II., III 46 | /// 47 | RomanNumberUpperPeriod, 48 | /// 49 | /// I), II), III) 50 | /// 51 | RomanNumberUpperParenthesis, 52 | /// 53 | /// i., ii., iii. 54 | /// 55 | RomanNumberLowerPeriod, 56 | /// 57 | /// i), ii), iii) 58 | /// 59 | RomanNumberLowerParenthesis 60 | } -------------------------------------------------------------------------------- /Text/Characters.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Text; 2 | 3 | public class Characters 4 | { 5 | public static string All = $"{Numbers}{Lower}{Special}{Upper}"; 6 | 7 | public static string LettersAndNumbers = $"{Numbers}{Lower}{Upper}"; 8 | 9 | public const string Numbers 10 | = "0123456789"; 11 | 12 | public const string Lower 13 | = "abcdefghijklmnopqrstuvwxyz"; 14 | 15 | public const string Special 16 | = "!@#$%^&*()-=_+[]{};':\",./<>?`~\\|"; 17 | 18 | public const string Upper 19 | = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 20 | } -------------------------------------------------------------------------------- /Text/Encoding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Text; 4 | 5 | [Serializable] 6 | public enum Encoding 7 | { 8 | ASCII, 9 | BigEndianUnicode, 10 | Default, 11 | Unicode, 12 | UTF32, 13 | UTF7, 14 | UTF8 15 | } -------------------------------------------------------------------------------- /Text/Expressions.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Text; 2 | 3 | public static class Expressions 4 | { 5 | public const string Guid 6 | = "^([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"; 7 | 8 | public const string Letters 9 | = "^[a-zA-Z]*$"; 10 | 11 | public const string LettersAndNumbers 12 | = "^[a-zA-Z0-9]*$"; 13 | 14 | public const string Numbers 15 | = "^[0-9]*$"; 16 | } -------------------------------------------------------------------------------- /Text/StringType.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Text; 2 | 3 | public enum StringType 4 | { 5 | Any, Alpha, AlphaNumerical, Numerical 6 | } -------------------------------------------------------------------------------- /Text/SymmetricAlgorithm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Text; 4 | 5 | [Serializable] 6 | public enum SymmetricAlgorithm 7 | { 8 | Aes, 9 | DES, 10 | RC2, 11 | Rijndael, 12 | TripleDES 13 | } -------------------------------------------------------------------------------- /Text/Wrapping.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Text; 2 | 3 | public enum Formats 4 | { 5 | Raw, MarkDown, MarkUp 6 | } 7 | 8 | public enum Wrapping 9 | { 10 | None, Wrap 11 | } 12 | 13 | public enum Trimming 14 | { 15 | None, 16 | Character, 17 | Word 18 | } -------------------------------------------------------------------------------- /Threading/IMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Threading; 4 | 5 | public interface IMethod 6 | { 7 | DateTime? LastActive { get; set; } 8 | } -------------------------------------------------------------------------------- /Threading/Operation.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Linq; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | namespace Imagin.Core.Threading; 6 | 7 | public class Operation : Method 8 | { 9 | public enum Statuses { Active, Inactive } 10 | 11 | public DateTime Added { get => Get(DateTime.Now); set => Set(value); } 12 | 13 | public OperationType Type { get => Get(OperationType.Create); set => Set(value); } 14 | 15 | public string Source { get => Get(""); set => Set(value); } 16 | 17 | public string Target { get => Get(""); set => Set(value); } 18 | 19 | public long SizeRead { get => Get(0L); set => Set(value); } 20 | 21 | public long Size { get => Get(0L); set => Set(value); } 22 | 23 | public double Speed => Duration.TotalSeconds == 0 ? 0 : SizeRead.Double() / Duration.TotalSeconds; 24 | 25 | public double Progress { get => Get(.0); set => Set(value); } 26 | 27 | public TimeSpan Duration { get => Get(TimeSpan.Zero); set => Set(value); } 28 | 29 | public Statuses Status { get => Get(Statuses.Inactive); set => Set(value); } 30 | 31 | public Operation(OperationType type, string source, string target, ManagedMethod action) : base(action) 32 | { 33 | Added = DateTime.Now; 34 | Type = type; 35 | Source = source; 36 | 37 | if (System.IO.File.Exists(source)) 38 | { 39 | var fileInfo = new System.IO.FileInfo(source); 40 | Size = fileInfo.Length; 41 | } 42 | 43 | Target = target; 44 | } 45 | 46 | public override void OnPropertyChanging(PropertyChangingEventArgs e) 47 | { 48 | base.OnPropertyChanging(e); 49 | if (e.PropertyName == nameof(Duration)) 50 | e.NewValue = TimeSpan.FromSeconds(e.NewValue.To().TotalSeconds.Round()); 51 | } 52 | 53 | public override void OnPropertyChanged(PropertyEventArgs e) 54 | { 55 | base.OnPropertyChanged(e); 56 | if (e.PropertyName == nameof(Duration) || e.PropertyName == nameof(SizeRead)) 57 | Update(() => Speed); 58 | } 59 | 60 | new public async Task Start() 61 | { 62 | Status = Statuses.Active; 63 | await base.Start(); 64 | Status = Statuses.Inactive; 65 | } 66 | } -------------------------------------------------------------------------------- /Threading/OperationType.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Threading; 2 | 3 | public enum OperationType 4 | { 5 | Create, 6 | Delete, 7 | Move 8 | } -------------------------------------------------------------------------------- /Threading/Queue.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Collections.ObjectModel; 2 | using System; 3 | 4 | namespace Imagin.Core.Threading; 5 | 6 | public class Queue : ObservableCollection 7 | { 8 | readonly IMethod method; 9 | 10 | public Operation Current { get; private set; } 11 | 12 | public Queue(IMethod method) 13 | { 14 | this.method = method; 15 | } 16 | 17 | async void Assign(Operation operation) 18 | { 19 | Current = operation; 20 | await Current.Start(); 21 | 22 | Remove(Current); 23 | Current = null; 24 | 25 | method.LastActive = DateTime.Now; 26 | Scan(); 27 | } 28 | 29 | void Scan() 30 | { 31 | if (Current == null) 32 | { 33 | if (Count > 0) 34 | { 35 | Assign(this[0]); 36 | } 37 | } 38 | } 39 | 40 | protected override void OnAdded(Operation input) 41 | { 42 | base.OnAdded(input); 43 | Scan(); 44 | } 45 | 46 | public void Add(OperationType type, string source, string target, ManagedMethod action) 47 | { 48 | Add(new Operation(type, source, target, action)); 49 | } 50 | 51 | new public void Clear() 52 | { 53 | foreach (var i in this) 54 | i.Cancel(); 55 | 56 | base.Clear(); 57 | } 58 | } -------------------------------------------------------------------------------- /Threading/TaskManagement.cs: -------------------------------------------------------------------------------- 1 | namespace Imagin.Core.Threading; 2 | 3 | public enum TaskManagement 4 | { 5 | /// Thread already started; calling method is already running on a new thread. Useful for quick operations. 6 | Managed, 7 | /// Thread not yet started; calling method is responsible for thread creation. Useful for working around UI operations. 8 | Unmanaged, 9 | } -------------------------------------------------------------------------------- /Threading/TaskQueue.cs: -------------------------------------------------------------------------------- 1 | using Imagin.Core.Input; 2 | using System; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace Imagin.Core.Threading; 7 | 8 | public class TaskQueue 9 | { 10 | readonly object Lock = new(); 11 | 12 | Task previousTask = Task.FromResult(true); 13 | 14 | CancellationTokenSource tokenSource = new(); 15 | 16 | /// 17 | 18 | /// 19 | /// Occurs when all tasks have cancelled. 20 | /// 21 | public event EventHandler Cancelled; 22 | 23 | /// 24 | /// Occurs when all tasks have completed. 25 | /// 26 | public event EventHandler Completed; 27 | 28 | /// 29 | /// Occurs when a task has completed. 30 | /// 31 | public event DefaultEventHandler TaskCompleted; 32 | 33 | /// 34 | 35 | int count = 0; 36 | public int Count 37 | { 38 | get 39 | { 40 | return count; 41 | } 42 | } 43 | 44 | bool isCancellationRequested = false; 45 | public bool IsCancellationRequested 46 | { 47 | get 48 | { 49 | return isCancellationRequested; 50 | } 51 | } 52 | 53 | /// 54 | 55 | public TaskQueue() 56 | { 57 | } 58 | 59 | /// 60 | 61 | public Task Add(Action Action) 62 | { 63 | lock (Lock) 64 | { 65 | count++; 66 | previousTask = previousTask.ContinueWith(i => 67 | { 68 | Action(); 69 | OnTaskCompleted(default(object)); 70 | }, 71 | tokenSource.Token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); 72 | return previousTask; 73 | } 74 | } 75 | 76 | public Task Add(Action Action) 77 | { 78 | lock (Lock) 79 | { 80 | count++; 81 | previousTask = previousTask.ContinueWith(i => 82 | { 83 | Action(tokenSource.Token); 84 | OnTaskCompleted(default(object)); 85 | }, 86 | tokenSource.Token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); 87 | return previousTask; 88 | } 89 | } 90 | 91 | public Task Add(Func Action) 92 | { 93 | lock (Lock) 94 | { 95 | previousTask = previousTask.ContinueWith(i => 96 | { 97 | var result = Action(); 98 | OnTaskCompleted(result); 99 | }, 100 | tokenSource.Token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); 101 | return previousTask; 102 | } 103 | } 104 | 105 | public Task Add(Func Action) 106 | { 107 | lock (Lock) 108 | { 109 | count++; 110 | previousTask = previousTask.ContinueWith(i => 111 | { 112 | var result = Action(tokenSource.Token); 113 | OnTaskCompleted(result); 114 | }, 115 | tokenSource.Token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); 116 | return previousTask; 117 | } 118 | } 119 | 120 | /// 121 | 122 | protected virtual void OnCancelled() 123 | { 124 | count = 0; 125 | previousTask = Task.FromResult(true); 126 | tokenSource = new CancellationTokenSource(); 127 | 128 | Cancelled?.Invoke(this, new EventArgs()); 129 | } 130 | 131 | protected virtual void OnCompleted() 132 | { 133 | Completed?.Invoke(this, new EventArgs()); 134 | } 135 | 136 | protected virtual void OnTaskCompleted(T input) 137 | { 138 | count--; 139 | TaskCompleted?.Invoke(this, new EventArgs(input)); 140 | if (count == 0) 141 | OnCompleted(); 142 | } 143 | 144 | /// 145 | 146 | public void CancelAll() 147 | { 148 | if (!IsCancellationRequested) 149 | { 150 | isCancellationRequested = true; 151 | tokenSource?.Cancel(); 152 | 153 | try 154 | { 155 | previousTask?.Wait(); 156 | } 157 | catch 158 | { 159 | //System.Diagnostics.Debug.WriteLine("Cancelled"); 160 | } 161 | finally 162 | { 163 | OnCancelled(); 164 | } 165 | isCancellationRequested = false; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /Time/BaseTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace Imagin.Core.Time; 5 | 6 | public abstract class BaseTimer 7 | { 8 | readonly Stopwatch stopwatch; 9 | 10 | public event EventHandler Started; 11 | 12 | public event EventHandler Stopped; 13 | 14 | public event TickEventHandler Tick; 15 | 16 | public virtual TimeSpan Interval { get; set; } 17 | 18 | protected BaseTimer() 19 | { 20 | stopwatch = new Stopwatch(); 21 | } 22 | 23 | protected virtual void OnStarted() 24 | { 25 | stopwatch.Start(); 26 | Started?.Invoke(this, new EventArgs()); 27 | } 28 | 29 | protected virtual void OnStopped() 30 | { 31 | stopwatch.Stop(); 32 | stopwatch.Reset(); 33 | Stopped?.Invoke(this, new EventArgs()); 34 | } 35 | 36 | protected virtual void OnTick() 37 | => Tick?.Invoke(this, new TickEventArgs(stopwatch.Elapsed)); 38 | } -------------------------------------------------------------------------------- /Time/Meridiem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Time; 4 | 5 | /// Specifies a time before or after midday. 6 | [Serializable] 7 | public enum Meridiem 8 | { 9 | /// Specifies a time BEFORE midday. 10 | AM, 11 | /// Specifies a time AFTER midday. 12 | PM 13 | } -------------------------------------------------------------------------------- /Time/Relativity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Time; 4 | 5 | [Serializable] 6 | public enum Relativity 7 | { 8 | Future, 9 | Past 10 | } -------------------------------------------------------------------------------- /Time/TickEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Time; 4 | 5 | public delegate void TickEventHandler(BaseTimer sender, TickEventArgs e); 6 | 7 | public class TickEventArgs : EventArgs 8 | { 9 | public readonly TimeSpan Elapsed; 10 | 11 | public TickEventArgs(TimeSpan elapsed) 12 | { 13 | Elapsed = elapsed; 14 | } 15 | } -------------------------------------------------------------------------------- /Time/Timer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imagin.Core.Time; 4 | 5 | public class Timer : BaseTimer 6 | { 7 | readonly System.Timers.Timer timer; 8 | 9 | public override TimeSpan Interval 10 | { 11 | get => TimeSpan.FromMilliseconds(timer.Interval); 12 | set => timer.Interval = value.TotalMilliseconds; 13 | } 14 | 15 | public Timer() : base() 16 | { 17 | timer = new System.Timers.Timer(); 18 | timer.Elapsed += OnTick; 19 | } 20 | 21 | public Timer(double interval) : this(TimeSpan.FromSeconds(interval)) { } 22 | 23 | public Timer(TimeSpan interval) : this() => Interval = interval; 24 | 25 | void OnTick(object sender, System.Timers.ElapsedEventArgs e) 26 | { 27 | OnTick(); 28 | } 29 | 30 | public void Start() 31 | { 32 | timer.Start(); 33 | OnStarted(); 34 | } 35 | 36 | public void Stop() 37 | { 38 | timer.Stop(); 39 | OnStopped(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "supports": { 3 | "net46.app": {}, 4 | "uwp.10.0.app": {} 5 | }, 6 | "dependencies": { 7 | "Microsoft.NETCore": "5.0.0", 8 | "Microsoft.NETCore.Portable.Compatibility": "1.0.0" 9 | }, 10 | "frameworks": { 11 | "dotnet": { 12 | "imports": "portable-net452+win81" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Imagin.Core ![](https://img.shields.io/badge/style-7.1-blue.svg?style=flat&label=Version) 2 | --- 3 | Core elements for shared projects. 4 | 5 | [Nuget](https://www.nuget.org/packages/Imagin.Core/) 6 | --- 7 | ### Quick install 8 | ##### Imagin.Core 9 | > _`Install-Package Imagin.Core -Version *.0.0`_ 10 | 11 | [Learn more...](https://github.com/imagin-code/Core/wiki/Getting-Started#install-with-nuget-coming-soon) 12 | 13 | Wiki ![](https://img.shields.io/badge/style-Coming%20soon!-red.svg?style=flat&label=) 14 | --- 15 | For help or to find out more, head over to [the wiki](https://github.com/imagin-code/Core/wiki/Getting-Started). 16 | 17 | Donate 18 | --- 19 | [![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AJJG6PWLBYQNG) --------------------------------------------------------------------------------