Compare commits
54 Commits
1.1.7448.2
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
baffd311ce | ||
|
5b5e359efb | ||
|
cae077a5cf | ||
|
d80c1ac5a0 | ||
|
9d87c47f1c | ||
|
bb5ea72041 | ||
|
454d902f04 | ||
|
fc68a0f6f7 | ||
|
dba8d63af5 | ||
|
65ae6b84e7 | ||
|
1e451b78f9 | ||
|
7c9a5aa73d | ||
|
85a67cd64a | ||
|
0fa5fd6e82 | ||
|
ea2572d585 | ||
|
0743b09941 | ||
|
45b7c9263c | ||
|
94bd0fa189 | ||
|
3fc3cd61b5 | ||
|
282a249f3f | ||
|
a24905c884 | ||
|
eb4d7fe2ec | ||
|
fdf8afb388 | ||
|
622d1aa130 | ||
|
4969a420ee | ||
|
f3cb5e136c | ||
|
5cb6fd677a | ||
|
f6644550a6 | ||
|
21ab015742 | ||
|
87b4f3fd08 | ||
|
d7fdd3a711 | ||
|
6b46c7950e | ||
|
db42601eba | ||
|
6b747bdbe8 | ||
|
4dfb57fc2f | ||
|
7699deb82c | ||
|
30e27b9a21 | ||
|
9e6b441169 | ||
|
5d380112ac | ||
|
d562ea5295 | ||
|
4abc39d48b | ||
|
b56fb7db78 | ||
|
c5fc9874b1 | ||
|
f0400a18bb | ||
|
f9e7fb1f40 | ||
|
46605e282e | ||
|
3f35a47e90 | ||
|
94d3ff2873 | ||
|
70fa52a59a | ||
|
a70f4f4393 | ||
|
fb44579b33 | ||
|
79531147b2 | ||
|
5f3fb98999 | ||
|
f6950a0d4c |
87
.github/workflows/main.yml
vendored
87
.github/workflows/main.yml
vendored
@ -1,87 +0,0 @@
|
||||
name: CD
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
id: base_init
|
||||
run: |
|
||||
$(new-object System.Net.WebClient).DownloadFile("https://www.github.com/JFronny/UpTool2/releases/latest/download/Tools.zip", "$($(pwd).Path)\Tools.zip")
|
||||
& "C:\Program Files\7-Zip\7z.exe" x .\Tools.zip
|
||||
rm Tools.zip
|
||||
rm Install.bat
|
||||
rm Remove.bat
|
||||
dotnet build --verbosity:m -p:Configuration=Release
|
||||
cp W32.Test\bin\Release\netcoreapp3.1\package.zip .
|
||||
$file = Get-Item $(Resolve-Path W32.Test\bin\Release\netcoreapp3.1\*.exe).Path
|
||||
$asm = $([Reflection.Assembly]::LoadFile($file.DirectoryName + "\" + $file.BaseName + ".dll"))
|
||||
$asmver = $asm.GetName().Version.ToString()
|
||||
echo "::set-output name=vers::$asmver"
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.base_init.outputs.vers }}
|
||||
release_name: Release ${{ steps.base_init.outputs.vers }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
- name: Upload Release Asset
|
||||
id: upload_release_asset
|
||||
uses: actions/upload-release-asset@v1.0.2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./package.zip
|
||||
asset_name: package.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Generate XML
|
||||
run: |
|
||||
$file = Get-Item $(Resolve-Path W32.Test\bin\Release\netcoreapp3.1\*.exe).Path
|
||||
$asm = [Reflection.Assembly]::LoadFile($file.DirectoryName + "\" + $file.BaseName + ".dll")
|
||||
[System.XML.XMLDocument]$xml=New-Object System.XML.XMLDocument
|
||||
[System.XML.XMLElement]$app=$xml.CreateElement("app")
|
||||
$xml.appendChild($app)
|
||||
$app.appendChild($xml.CreateElement("Name")).InnerText = $asm.GetName().Name
|
||||
$app.appendChild($xml.CreateElement("Description")).InnerText = "Collection of Utilities for manipulating Windows"
|
||||
$app.appendChild($xml.CreateElement("Version")).InnerText = "${{ steps.base_init.outputs.vers }}"
|
||||
$app.appendChild($xml.CreateElement("ID")).InnerText = "3191d2f3-bf48-48ea-97a2-59fb32722d0a"
|
||||
$app.appendChild($xml.CreateElement("File")).InnerText = "${{ steps.upload_release_asset.outputs.browser_download_url }}"
|
||||
$app.appendChild($xml.CreateElement("Hash")).InnerText = $(Get-FileHash .\package.zip).Hash
|
||||
$app.appendChild($xml.CreateElement("MainFile")).InnerText = $file.Name
|
||||
echo NULL > app.xml
|
||||
$xml.save($(gi .\app.xml).Fullname)
|
||||
- name: Upload XML
|
||||
uses: actions/upload-release-asset@v1.0.2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./app.xml
|
||||
asset_name: app.xml
|
||||
asset_content_type: text/xml
|
||||
- name: Publish nugets
|
||||
run: |
|
||||
$tmp = "${{ steps.base_init.outputs.vers }}"
|
||||
$tmp1 = $tmp.split('.')[2]
|
||||
$tmp2 = $tmp.split('.')[3]
|
||||
$suffix = "$tmp1.$tmp2"
|
||||
cd Misc
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
dotnet nuget push $(Get-Item $(Resolve-Path *.nupkg).Path).Name -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json
|
||||
cd ..\W32
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
dotnet nuget push $(Get-Item $(Resolve-Path *.nupkg).Path).Name -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json
|
||||
cd ..\Commandline
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
dotnet nuget push $(Get-Item $(Resolve-Path *.nupkg).Path).Name -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json
|
||||
cd ..
|
85
.gitlab-ci.yml
Normal file
85
.gitlab-ci.yml
Normal file
@ -0,0 +1,85 @@
|
||||
.shared_windows_runners:
|
||||
tags:
|
||||
- windows
|
||||
|
||||
image: mcr.microsoft.com/dotnet/sdk
|
||||
|
||||
uptool:
|
||||
extends:
|
||||
- .shared_windows_runners
|
||||
stage: deploy
|
||||
script: |
|
||||
mkdir i
|
||||
cd i
|
||||
$(new-object System.Net.WebClient).DownloadFile("https://gitlab.com/JFronny/UpTool2/-/jobs/artifacts/master/raw/Installer-generic.zip?job=uptool", "$($(pwd).Path)\Install.zip")
|
||||
& "C:\Program Files\7-Zip\7z.exe" x .\Install.zip
|
||||
.\Installer.exe --basic i -p
|
||||
cd ..
|
||||
rm -R i
|
||||
$Env:Path="$Env:Path;$Env:APPDATA\UpTool2\Install"
|
||||
uptool --basic add-repo DevTools https://gitlab.com/JFronny/UpTool2/-/snippets/2010392/raw
|
||||
uptool --basic update
|
||||
uptool --basic install "UpTool2 package tools"
|
||||
$Env:Path="$Env:Path;$Env:APPDATA\UpTool2\Apps\0e35d154-d0d3-45e0-b080-62f521263a44\app"
|
||||
|
||||
mkdir .\build
|
||||
cd W32.Test
|
||||
dotnet publish -o ..\build -c Release
|
||||
cd ..
|
||||
$file = Get-Item $(Resolve-Path .\build\*.exe).Path
|
||||
pkgtool build --binDir build --mainBin $file --packageFile .\package.zip --noLogo
|
||||
$asm = $([Reflection.Assembly]::LoadFile($file.DirectoryName + "\" + $file.BaseName + ".dll"))
|
||||
$asmver = $asm.GetName().Version.ToString()
|
||||
[System.XML.XMLDocument]$xml=New-Object System.XML.XMLDocument
|
||||
[System.XML.XMLElement]$app=$xml.CreateElement("app")
|
||||
$xml.appendChild($app)
|
||||
$app.appendChild($xml.CreateElement("Name")).InnerText = $asm.GetName().Name
|
||||
$app.appendChild($xml.CreateElement("Description")).InnerText = "Collection of Utilities for manipulating Windows"
|
||||
$app.appendChild($xml.CreateElement("Version")).InnerText = $asmver
|
||||
$app.appendChild($xml.CreateElement("ID")).InnerText = "3191d2f3-bf48-48ea-97a2-59fb32722d0a"
|
||||
$app.appendChild($xml.CreateElement("File")).InnerText = $CI_PROJECT_URL + "/-/jobs/" + $CI_JOB_ID + "/artifacts/raw/package.zip"
|
||||
$app.appendChild($xml.CreateElement("Hash")).InnerText = $(Get-FileHash .\package.zip).Hash
|
||||
$app.appendChild($xml.CreateElement("MainFile")).InnerText = $file.Name
|
||||
echo NULL > app.xml
|
||||
$xml.save($(gi .\app.xml).Fullname)
|
||||
$tmp1 = $asmver.split('.')[2]
|
||||
$tmp2 = $asmver.split('.')[3]
|
||||
$suffix = "$tmp1.$tmp2"
|
||||
cd Core
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
|
||||
echo $tmp
|
||||
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
|
||||
cd ..\Misc
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
|
||||
echo $tmp
|
||||
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
|
||||
cd ..\AspNet
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
|
||||
echo $tmp
|
||||
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
|
||||
cd ..\W32
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
|
||||
echo $tmp
|
||||
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
|
||||
cd ..\Commandline
|
||||
dotnet pack --version-suffix "$suffix" -c Release -o .
|
||||
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
|
||||
echo $tmp
|
||||
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
|
||||
cd ..
|
||||
mkdir nugets
|
||||
cp .\Core\*.nupkg .\nugets\
|
||||
cp .\Misc\*.nupkg .\nugets\
|
||||
cp .\W32\*.nupkg .\nugets\
|
||||
cp .\Commandline\*.nupkg .\nugets\
|
||||
artifacts:
|
||||
paths:
|
||||
- package.zip
|
||||
- app.xml
|
||||
- nugets
|
||||
only:
|
||||
- master
|
33
AspNet/AspNet.csproj
Normal file
33
AspNet/AspNet.csproj
Normal file
@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>CC_Functions.AspNet</RootNamespace>
|
||||
<AssemblyName>CC_Functions.AspNet</AssemblyName>
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.AspNet</PackageId>
|
||||
<Title>CC-Functions.AspNet</Title>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>Random pieces of code for Asp.Net, including my SerialDict integrated Database</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<VersionSuffix>0.0</VersionSuffix>
|
||||
<PackageVersion>1.1.$(VersionSuffix)</PackageVersion>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DocumentationFile>bin\Debug\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\Release\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="protobuf-net" Version="3.0.62" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
138
AspNet/DictionaryGuidConverter.cs
Normal file
138
AspNet/DictionaryGuidConverter.cs
Normal file
@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides serializing dictionary with Guid keys
|
||||
/// </summary>
|
||||
public class DictionaryGuidConverter : JsonConverterFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
if (!typeToConvert.IsGenericType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeToConvert.GetGenericArguments()[0] == typeof(Guid);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
Type valueType = typeToConvert.GetGenericArguments()[1];
|
||||
|
||||
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
|
||||
typeof(DictionaryGuidConverterInner<>).MakeGenericType(valueType),
|
||||
BindingFlags.Instance | BindingFlags.Public,
|
||||
null,
|
||||
new object[] { options },
|
||||
null);
|
||||
|
||||
return converter;
|
||||
}
|
||||
|
||||
private class DictionaryGuidConverterInner<TValue> : JsonConverter<Dictionary<Guid, TValue>>
|
||||
{
|
||||
private readonly JsonConverter<TValue> _valueConverter;
|
||||
private Type _valueType;
|
||||
|
||||
public DictionaryGuidConverterInner(JsonSerializerOptions options)
|
||||
{
|
||||
// For performance, use the existing converter if available.
|
||||
_valueConverter = (JsonConverter<TValue>)options
|
||||
.GetConverter(typeof(TValue));
|
||||
|
||||
// Cache the key and value types.
|
||||
_valueType = typeof(TValue);
|
||||
}
|
||||
|
||||
public override Dictionary<Guid, TValue> Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
Dictionary<Guid, TValue> dictionary = new Dictionary<Guid, TValue>();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.EndObject)
|
||||
{
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
// Get the key.
|
||||
if (reader.TokenType != JsonTokenType.PropertyName)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
string propertyName = reader.GetString();
|
||||
|
||||
// For performance, parse with ignoreCase:false first.
|
||||
if (!Guid.TryParse(propertyName, out Guid key))
|
||||
{
|
||||
throw new JsonException(
|
||||
$"Unable to convert \"{propertyName}\" to Guid.");
|
||||
}
|
||||
|
||||
// Get the value.
|
||||
TValue v;
|
||||
if (_valueConverter != null)
|
||||
{
|
||||
reader.Read();
|
||||
v = _valueConverter.Read(ref reader, _valueType, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = JsonSerializer.Deserialize<TValue>(ref reader, options);
|
||||
}
|
||||
|
||||
// Add to dictionary.
|
||||
dictionary.Add(key, v);
|
||||
}
|
||||
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
Dictionary<Guid, TValue> dictionary,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach (KeyValuePair<Guid, TValue> kvp in dictionary)
|
||||
{
|
||||
writer.WritePropertyName(kvp.Key.ToString());
|
||||
|
||||
if (_valueConverter != null)
|
||||
{
|
||||
_valueConverter.Write(writer, kvp.Value, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonSerializer.Serialize(writer, kvp.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
AspNet/GenericExtensions.cs
Normal file
21
AspNet/GenericExtensions.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for various types
|
||||
/// </summary>
|
||||
public static class GenericExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Include CCF json extensions for this serializer
|
||||
/// </summary>
|
||||
/// <param name="options">The options to include CCF in</param>
|
||||
/// <returns>The options including CCF</returns>
|
||||
public static JsonSerializerOptions AddCcf(this JsonSerializerOptions options)
|
||||
{
|
||||
options.Converters.Add(new DictionaryGuidConverter());
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
164
AspNet/SaveLoadDict.cs
Normal file
164
AspNet/SaveLoadDict.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides synchronizing for dictionaries with saving/loading backends
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The key type</typeparam>
|
||||
/// <typeparam name="U">The param type</typeparam>
|
||||
public abstract class SaveLoadDict<T, U> : IDictionary<T, U>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<KeyValuePair<T, U>> GetEnumerator()
|
||||
{
|
||||
lock (this) return Load().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
lock (this) return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this) Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
lock (this) Save(new Dictionary<T, U>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this) return Load().Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(KeyValuePair<T, U>[] array, int arrayIndex)
|
||||
{
|
||||
lock (this) Load().CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
try
|
||||
{
|
||||
return dictionary.Remove(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count
|
||||
{
|
||||
get { lock (this) return Load().Count; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(T key, U value)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
dictionary.Add(key, value);
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsKey(T key)
|
||||
{
|
||||
lock (this) return Load().ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(T key)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
try
|
||||
{
|
||||
return dictionary.Remove(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(T key, out U value)
|
||||
{
|
||||
lock (this) return Load().TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public U this[T key]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this) return Load()[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
dictionary[key] = value;
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<T> Keys
|
||||
{
|
||||
get { lock (this) return Load().Keys; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<U> Values
|
||||
{
|
||||
get { lock (this) return Load().Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace the current content based on the current state
|
||||
/// </summary>
|
||||
/// <param name="f">Function to mutate the content</param>
|
||||
public void Mutate(Func<IDictionary<T, U>, IDictionary<T, U>> f)
|
||||
{
|
||||
lock (this) Save(f(Load()));
|
||||
}
|
||||
/// <summary>
|
||||
/// Save the dictionary content
|
||||
/// </summary>
|
||||
/// <param name="v">Dictionary content to save</param>
|
||||
protected abstract void Save(IDictionary<T, U> v);
|
||||
/// <summary>
|
||||
/// Load the content to a dictionary
|
||||
/// </summary>
|
||||
/// <returns>The loaded content</returns>
|
||||
protected abstract IDictionary<T, U> Load();
|
||||
}
|
||||
}
|
73
AspNet/SerialDict.cs
Normal file
73
AspNet/SerialDict.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of SaveLoadDict that uses Protobuf-net for serialization and Guid keys
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data type</typeparam>
|
||||
public abstract class SerialDict<T> : SaveLoadDict<Guid, T>
|
||||
{
|
||||
//Interface
|
||||
/// <summary>
|
||||
/// Gets the directory containing databases
|
||||
/// </summary>
|
||||
public abstract string DatabasesDir { get; }
|
||||
/// <summary>
|
||||
/// Gets the file name for this database. Must not contain the path
|
||||
/// </summary>
|
||||
public abstract string DatabaseFileName { get; }
|
||||
/// <summary>
|
||||
/// Called when the database is loaded. Use for preparing initial entries
|
||||
/// </summary>
|
||||
public event LoadedD Loaded;
|
||||
/// <summary>
|
||||
/// Called when the database is loaded. Use for preparing initial entries
|
||||
/// </summary>
|
||||
/// <param name="v">The current dictionary content</param>
|
||||
public delegate void LoadedD(IDictionary<Guid, T> v);
|
||||
/// <summary>
|
||||
/// Loads the dictionary and replaces Guids with strings. Use for sending
|
||||
/// </summary>
|
||||
/// <returns>The simplified dictionary</returns>
|
||||
public IDictionary<string, T> GetSendable() => Load().ToDictionary(s => s.Key.ToString(), s => s.Value);
|
||||
|
||||
//Internal
|
||||
private string GetRel() => Path.Combine(DatabasesDir, DatabaseFileName);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IDictionary<Guid, T> Load()
|
||||
{
|
||||
if (!Directory.Exists(DatabasesDir))
|
||||
Directory.CreateDirectory(DatabasesDir);
|
||||
IDictionary<Guid, T> v;
|
||||
if (File.Exists(GetRel()))
|
||||
{
|
||||
using (FileStream file = File.OpenRead(GetRel()))
|
||||
v = Serializer.Deserialize<Dictionary<Guid, T>>(file);
|
||||
Loaded?.Invoke(v);
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = new Dictionary<Guid, T>();
|
||||
Loaded?.Invoke(v);
|
||||
Save(v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Save(IDictionary<Guid, T> dict)
|
||||
{
|
||||
if (!Directory.Exists(DatabasesDir))
|
||||
Directory.CreateDirectory(DatabasesDir);
|
||||
using FileStream file = File.Create(GetRel());
|
||||
Serializer.Serialize(file, dict);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commandline", "Commandline\
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLITest", "CLITest\CLITest.csproj", "{3FAB0713-3021-4C6A-BF4A-ABBD542634A6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{780EC190-E223-46DE-B6FB-1CF56ABDF34E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet", "AspNet\AspNet.csproj", "{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -39,6 +43,14 @@ Global
|
||||
{3FAB0713-3021-4C6A-BF4A-ABBD542634A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3FAB0713-3021-4C6A-BF4A-ABBD542634A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3FAB0713-3021-4C6A-BF4A-ABBD542634A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1,78 +1,107 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using CC_Functions.Commandline;
|
||||
using CC_Functions.Commandline.TUI;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CLITest
|
||||
{
|
||||
class Program
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
private static void Main()
|
||||
{
|
||||
Thread.CurrentThread.ForceInvariantCulture();
|
||||
//Parse test
|
||||
if (new ArgsParse(new[] { "--meme", "Fuk u", "--meme:yeet", "--meme:yote", "--meme" })["meme"] != "yote")
|
||||
throw new Exception("ArgsParse error 1");
|
||||
if (!new ArgsParse(new[] { "--meme", "Fuk u", "--meme:yeet", "--meme:yote", "--meme" }).GetBool("meme"))
|
||||
throw new Exception("ArgsParse error 2");
|
||||
if (new ArgsParse(new[] {"--meme:"}).GetBool("meme"))
|
||||
throw new Exception("ArgsParse error 3");
|
||||
if (!new ArgsParse(new[] {"--meme:true"}).GetBool("mEme"))
|
||||
throw new Exception("ArgsParse error 4");
|
||||
if (new ArgsParse(new[] {"--meme:1.1.2019"}).Get<DateTime>("meme") != new DateTime(2019, 1, 1))
|
||||
throw new Exception("ArgsParse error 5");
|
||||
if (new ArgsParse(new[] {"--meme:2019"}).Get("meme", s => s == null ? DateTime.Now : DateTime.Parse("1.1." + s)) != new DateTime(2019, 1, 1))
|
||||
throw new Exception("ArgsParse error 6");
|
||||
|
||||
//Display test
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.Clear();
|
||||
Screen screen = new Screen(40, 20);
|
||||
CenteredScreen cScreen = new CenteredScreen(40, 20, ConsoleColor.Green);
|
||||
Panel screen = cScreen.ContentPanel;
|
||||
Button btn1 = new Button("Test")
|
||||
{
|
||||
Point = new Point(2, 0)
|
||||
Point = new Point(2, 0),
|
||||
BackColor = ConsoleColor.DarkGreen
|
||||
};
|
||||
screen.Controls.Add(btn1);
|
||||
btn1.Click += (screen1, eventArgs) =>
|
||||
{
|
||||
DiffDraw.FullDraw(true);
|
||||
};
|
||||
btn1.Click += (screen1, eventArgs) => { DiffDraw.Draw(true, true); };
|
||||
Label lab1 = new Label("Meem")
|
||||
{
|
||||
Point = new Point(2, 1)
|
||||
Point = new Point(2, 1),
|
||||
BackColor = ConsoleColor.Green
|
||||
};
|
||||
screen.Controls.Add(lab1);
|
||||
screen.Controls.Add(new Label("Saas\nSoos")
|
||||
{
|
||||
Point = new Point(2, 2)
|
||||
Point = new Point(2, 2),
|
||||
BackColor = ConsoleColor.Green
|
||||
});
|
||||
Button btn2 = new Button("X");
|
||||
Button btn2 = new Button("X")
|
||||
{
|
||||
BackColor = ConsoleColor.Red,
|
||||
ForeColor = ConsoleColor.White
|
||||
};
|
||||
screen.Controls.Add(btn2);
|
||||
|
||||
CheckBox box = new CheckBox("Are u gae?")
|
||||
{
|
||||
Point = new Point(2, 3)
|
||||
Point = new Point(2, 3),
|
||||
BackColor = ConsoleColor.DarkGreen
|
||||
};
|
||||
screen.Controls.Add(box);
|
||||
box.CheckedChanged += (screen1, eventArgs) =>
|
||||
{
|
||||
lab1.Content = box.Checked ? "Sas" : "Meem";
|
||||
};
|
||||
box.CheckedChanged += (screen1, eventArgs) => { lab1.Content = box.Checked ? "Sas" : "Meem"; };
|
||||
|
||||
TextBox tbox = new TextBox("Hello\nWorld1\n\nHow are u?")
|
||||
{
|
||||
Size = new Size(20, 10),
|
||||
Point = new Point(0, 6)
|
||||
Point = new Point(0, 6),
|
||||
BackColor = ConsoleColor.DarkYellow
|
||||
};
|
||||
screen.Controls.Add(tbox);
|
||||
|
||||
Slider slider = new Slider
|
||||
{
|
||||
Point = new Point(2, 4),
|
||||
Size = new Size(8, 2),
|
||||
Size = new Size(16, 2),
|
||||
MaxValue = 75,
|
||||
StepSize = 14,
|
||||
MinValue = -3,
|
||||
Value = 7
|
||||
Value = 7,
|
||||
BackColor = ConsoleColor.Magenta
|
||||
};
|
||||
screen.Controls.Add(slider);
|
||||
|
||||
bool visible = true;
|
||||
btn2.Click += (screen1, eventArgs) => visible = false;
|
||||
screen.Close += (screen1, eventArgs) => visible = false;
|
||||
screen.Render();
|
||||
cScreen.Close += (screen1, eventArgs) => visible = false;
|
||||
cScreen.TabChanged += (screen1, eventArgs) => btn1.Content = $"Test {cScreen.TabPoint}";
|
||||
cScreen.Render();
|
||||
while (visible)
|
||||
{
|
||||
Thread.Sleep(50);
|
||||
screen.ReadInput();
|
||||
cScreen.ReadInput();
|
||||
}
|
||||
Console.ResetColor();
|
||||
Console.Clear();
|
||||
Console.WriteLine("Test2");
|
||||
Thread.Sleep(100);
|
||||
DiffDraw.Clear(10, 10);
|
||||
DiffDraw.Draw(true, false);
|
||||
Console.Clear();
|
||||
Console.WriteLine("Bye");
|
||||
}
|
||||
}
|
||||
|
98
Commandline/ArgsParse.cs
Normal file
98
Commandline/ArgsParse.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace CC_Functions.Commandline
|
||||
{
|
||||
/// <summary>
|
||||
/// A class to provide basic parsing for program arguments
|
||||
/// </summary>
|
||||
public class ArgsParse : IEnumerable<string>
|
||||
{
|
||||
private readonly string[] _args;
|
||||
/// <summary>
|
||||
/// Create a new instance based on the specified args
|
||||
/// </summary>
|
||||
/// <param name="args">The inputted args. Should be a parameter of the main method</param>
|
||||
public ArgsParse(string[] args) => _args = args ?? throw new NullReferenceException();
|
||||
/// <summary>
|
||||
/// Shadowed from the base args
|
||||
/// </summary>
|
||||
/// <param name="i">The index in the base args</param>
|
||||
public string this[int i]
|
||||
{
|
||||
get => _args[i];
|
||||
set => _args[i] = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Shadowed from the base args
|
||||
/// </summary>
|
||||
/// <returns>An enumerator for the base args</returns>
|
||||
IEnumerator<string> IEnumerable<string>.GetEnumerator() => ((IEnumerable<string>)_args).GetEnumerator();
|
||||
/// <summary>
|
||||
/// Shadowed from the base args
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerator GetEnumerator() => _args.GetEnumerator();
|
||||
/// <summary>
|
||||
/// Gets the string specified for this key or null
|
||||
/// </summary>
|
||||
/// <param name="i">The name of the parameter</param>
|
||||
public string? this[string i]
|
||||
{
|
||||
get
|
||||
{
|
||||
string? selected = null;
|
||||
foreach (string s in _args)
|
||||
if (s.TrimStart('-', '/').ToLower().StartsWith($"{i.ToLower()}:"))
|
||||
selected = string.Join("", s.TrimStart('-', '/').Skip(i.Length + 1));
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the string specified for this key or null
|
||||
/// </summary>
|
||||
/// <param name="i">The name of the parameter</param>
|
||||
/// <returns>The value or null</returns>
|
||||
public string? GetString(string i) => this[i];
|
||||
/// <summary>
|
||||
/// Gets a boolean value with the specified name. Either specified as --i or --i:true
|
||||
/// </summary>
|
||||
/// <param name="i">The name of the parameter</param>
|
||||
/// <returns>The value</returns>
|
||||
public bool GetBool(string i) => _args.Any(s => s.ToLower().TrimStart('-', '/') == i.ToLower()) || bool.TryParse(this[i], out bool res) && res;
|
||||
/// <summary>
|
||||
/// Gets an arg using a transformer specified by you. The value passed will be the same as this[i]
|
||||
/// </summary>
|
||||
/// <param name="i">The name of the parameter</param>
|
||||
/// <param name="func">A null-safe function to convert a string to the expected type</param>
|
||||
/// <typeparam name="T">The type to convert to</typeparam>
|
||||
/// <returns>The converted value</returns>
|
||||
public T Get<T>(string i, Func<string?, T> func) => func(this[i]);
|
||||
/// <summary>
|
||||
/// Uses reflection to call the Parse method on types providing it. Use Get() with a func param for other types
|
||||
/// This will return null if the type is not found
|
||||
/// </summary>
|
||||
/// <param name="i">The name of the parameter</param>
|
||||
/// <typeparam name="T">The type to convert to</typeparam>
|
||||
/// <returns>The converted value</returns>
|
||||
public T Get<T>(string i)
|
||||
{
|
||||
MethodInfo[] parse = typeof(T).GetMethods().Where(s => s.Name.ToLower() == "parse"
|
||||
&& s.GetParameters().Length == 1
|
||||
&& s.GetParameters()[0].ParameterType == typeof(string)
|
||||
&& s.ReturnType == typeof(T)
|
||||
&& !s.IsAbstract && !s.IsPrivate && s.IsStatic).ToArray();
|
||||
if (parse.Length == 0)
|
||||
throw new InvalidOperationException("Could not find a valid parse method");
|
||||
string? v = this[i];
|
||||
if (v == null)
|
||||
return default;
|
||||
return (T) parse[0].Invoke(null, new object[] {v});
|
||||
}
|
||||
}
|
||||
}
|
@ -9,16 +9,17 @@
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.Commandline</PackageId>
|
||||
<Title>CC-Functions.Commandline</Title>
|
||||
<Authors>CC24</Authors>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>Random pieces of code used across my projects. CLI/TUI extensions</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://github.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<VersionSuffix>0.0</VersionSuffix>
|
||||
<PackageVersion>1.1.$(VersionSuffix)</PackageVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
@ -30,7 +31,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Misc\Misc.csproj" />
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,34 +1,40 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Commandline.TUI;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
namespace CC_Functions.Commandline
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides differential drawing of a char[,] Do not use in combination with System.Console
|
||||
/// </summary>
|
||||
public static class DiffDraw
|
||||
{
|
||||
private static Pixel[,] Screen { get; set; } = new Pixel[0, 0];
|
||||
private static Pixel[,] _last = new Pixel[0, 0];
|
||||
private static Pixel[,] Screen { get; set; } = new Pixel[0, 0];
|
||||
|
||||
/// <summary>
|
||||
/// The regions width
|
||||
/// </summary>
|
||||
public static int Width => Screen.GetLength(1);
|
||||
|
||||
/// <summary>
|
||||
/// The regions height
|
||||
/// </summary>
|
||||
public static int Height => Screen.GetLength(0);
|
||||
|
||||
/// <summary>
|
||||
/// Draws to the console
|
||||
/// </summary>
|
||||
/// <param name="color">Whether to use color</param>
|
||||
public static void Draw(bool color)
|
||||
/// <param name="full">Whether to redraw the entire screen (should be done from time to time to prevent corruption)</param>
|
||||
public static void Draw(bool color, bool full = false)
|
||||
{
|
||||
Console.CursorTop = 0;
|
||||
Console.CursorLeft = 0;
|
||||
ConsoleColor fcol = Console.ForegroundColor;
|
||||
ConsoleColor bcol = Console.BackgroundColor;
|
||||
ConsoleColor fCol = Console.ForegroundColor;
|
||||
ConsoleColor bCol = Console.BackgroundColor;
|
||||
if (full) Console.Clear();
|
||||
int width = Width;
|
||||
int height = Height;
|
||||
for (int y = 0; y < height; y++)
|
||||
@ -36,61 +42,32 @@ namespace CC_Functions.Commandline.TUI
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Pixel tmp1 = Screen[y, x];
|
||||
if (tmp1 == _last[y, x]) continue;
|
||||
if (color)
|
||||
if (!full && tmp1 == _last[y, x]) continue;
|
||||
if (!ReferenceEquals(tmp1, null) && color)
|
||||
{
|
||||
if (Console.ForegroundColor != tmp1.ForeColor)
|
||||
Console.ForegroundColor = tmp1.ForeColor;
|
||||
if (Console.BackgroundColor != tmp1.BackColor)
|
||||
Console.BackgroundColor = tmp1.BackColor;
|
||||
}
|
||||
Console.CursorLeft = x;
|
||||
Console.Write(tmp1);
|
||||
Console.Write(tmp1 ?? Pixel.Empty);
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.CursorLeft = 0;
|
||||
}
|
||||
Console.ForegroundColor = fcol;
|
||||
Console.BackgroundColor = bcol;
|
||||
_last = Screen;
|
||||
}
|
||||
/// <summary>
|
||||
/// Redraws the entire screen (should be done from time to time to prevent corruption)
|
||||
/// </summary>
|
||||
/// <param name="color">Whether to use color</param>
|
||||
public static void FullDraw(bool color)
|
||||
{
|
||||
Console.CursorTop = 0;
|
||||
Console.CursorLeft = 0;
|
||||
ConsoleColor fcol = Console.ForegroundColor;
|
||||
ConsoleColor bcol = Console.BackgroundColor;
|
||||
Console.Clear();
|
||||
int width = Width;
|
||||
int height = Height;
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
Pixel tmp1 = Screen[y, x];
|
||||
if (color)
|
||||
{
|
||||
Console.ForegroundColor = tmp1.ForeColor;
|
||||
Console.BackgroundColor = tmp1.BackColor;
|
||||
}
|
||||
Console.CursorLeft = x;
|
||||
Console.Write(tmp1);
|
||||
}
|
||||
Console.WriteLine();
|
||||
Console.CursorLeft = 0;
|
||||
}
|
||||
Console.ForegroundColor = fcol;
|
||||
Console.BackgroundColor = bcol;
|
||||
Console.ForegroundColor = fCol;
|
||||
Console.BackgroundColor = bCol;
|
||||
_last = Screen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the char at a location
|
||||
/// </summary>
|
||||
/// <param name="p">The location</param>
|
||||
/// <returns>The char</returns>
|
||||
public static char Get(Point p) => Get(p.X, p.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the char at a location
|
||||
/// </summary>
|
||||
@ -98,12 +75,14 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <param name="y">The locations Y coordinate</param>
|
||||
/// <returns>The char</returns>
|
||||
public static char Get(int x, int y) => Screen[y, x].Content;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the foreground color at a location
|
||||
/// </summary>
|
||||
/// <param name="p">The location</param>
|
||||
/// <returns>The color</returns>
|
||||
public static ConsoleColor GetForeColor(Point p) => GetForeColor(p.X, p.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the foreground color at a location
|
||||
/// </summary>
|
||||
@ -111,12 +90,14 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <param name="y">The locations Y coordinate</param>
|
||||
/// <returns>The color</returns>
|
||||
public static ConsoleColor GetForeColor(int x, int y) => Screen[y, x].ForeColor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the background color at a location
|
||||
/// </summary>
|
||||
/// <param name="p">The location</param>
|
||||
/// <returns>The color</returns>
|
||||
public static ConsoleColor GetBackColor(Point p) => GetBackColor(p.X, p.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the background color at a location
|
||||
/// </summary>
|
||||
@ -124,12 +105,14 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <param name="y">The locations Y coordinate</param>
|
||||
/// <returns>The color</returns>
|
||||
public static ConsoleColor GetBackColor(int x, int y) => Screen[y, x].BackColor;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a pixel at a point
|
||||
/// </summary>
|
||||
/// <param name="p">The point to place at</param>
|
||||
/// <param name="c">The pixel to place</param>
|
||||
public static void Set(Point p, Pixel c) => Set(p.X, p.Y, c);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a pixel at a location
|
||||
/// </summary>
|
||||
@ -137,10 +120,12 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <param name="y">The locations Y coordinate</param>
|
||||
/// <param name="c">The pixel to place</param>
|
||||
public static void Set(int x, int y, Pixel c) => Screen[y, x] = c;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the screen
|
||||
/// </summary>
|
||||
public static void Clear() => Clear(Width, Height);
|
||||
|
||||
/// <summary>
|
||||
/// Resizes and clears the screen
|
||||
/// </summary>
|
||||
@ -151,6 +136,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
Screen = new Pixel[height, width];
|
||||
_last = _last.Resize(height, width);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the screen state
|
||||
/// </summary>
|
@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using CC_Functions.Misc;
|
||||
using System.Linq;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -12,6 +14,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// The text inside this button
|
||||
/// </summary>
|
||||
public string Content;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new button
|
||||
/// </summary>
|
||||
@ -20,22 +23,45 @@ namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
Content = content;
|
||||
char[,] tmp = Content.ToNdArray2D();
|
||||
Size = new Size(tmp.GetLength(0), tmp.GetLength(1));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
char[,] inp = Content.ToNdArray2D();
|
||||
inp = inp.Resize(Size.Width, Size.Height);
|
||||
Pixel[,] output = new Pixel[Size.Width, Size.Height];
|
||||
for (int x = 0; x < Size.Width; x++)
|
||||
for (int y = 0; y < Size.Height; y++)
|
||||
output[x, y] = new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor, inp[x, y]);
|
||||
return output;
|
||||
Size = new Size(tmp.GetLength(1), tmp.GetLength(0));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
char[,] inp = Indent(SplitLines(Content, Size.Width), Size.Width).ToNdArray2D();
|
||||
inp = inp.Resize(Size.Height, Size.Width);
|
||||
Pixel[,] output = new Pixel[Size.Height, Size.Width];
|
||||
for (int x = 0; x < Size.Height; x++)
|
||||
for (int y = 0; y < Size.Width; y++)
|
||||
output[x, y] = new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor, inp[x, y]);
|
||||
return output;
|
||||
}
|
||||
|
||||
private string Indent(string source, int maxLen)
|
||||
{
|
||||
string[] tmp = source.Split('\n');
|
||||
for (int i = 0; i < tmp.Length; i++) tmp[i] = new string(SpecialChars.Empty, (maxLen - tmp[i].Length) / 2) + tmp[i];
|
||||
return string.Join('\n', tmp);
|
||||
}
|
||||
|
||||
private string SplitLines(string source, int maxLen)
|
||||
{
|
||||
List<string> parts = new List<string>(source.Split());
|
||||
while (parts.Any(s => s.Length > maxLen))
|
||||
{
|
||||
parts = parts.SelectMany(s =>
|
||||
{
|
||||
if (s.Length > maxLen)
|
||||
return s.Insert(maxLen, "\n").Split('\n');
|
||||
else
|
||||
return new[] {s};
|
||||
}).ToList();
|
||||
}
|
||||
return string.Join('\n', parts);
|
||||
}
|
||||
}
|
||||
}
|
97
Commandline/TUI/CenteredScreen.cs
Normal file
97
Commandline/TUI/CenteredScreen.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a screen that stays in the middle of the console. Use ContentPanel to attach controls
|
||||
/// </summary>
|
||||
public class CenteredScreen : Screen
|
||||
{
|
||||
private bool _resizing;
|
||||
private Size _actualSize;
|
||||
|
||||
/// <summary>
|
||||
/// The panel used for storing and rendering the actual controls
|
||||
/// </summary>
|
||||
public Panel ContentPanel;
|
||||
|
||||
private string _title = "CC-Functions.CommandLine app";
|
||||
private readonly Label _titleLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a screen that stays in the middle of the console. Use ContentPanel to attach controls
|
||||
/// </summary>
|
||||
/// <param name="width">The width of the content panel</param>
|
||||
/// <param name="height">The height of the content panel</param>
|
||||
/// <param name="contentBack">The content panels background (Should be different from Console.BackgroundColor)</param>
|
||||
/// <param name="color">Whether to use color when drawing</param>
|
||||
public CenteredScreen(int width, int height, ConsoleColor contentBack, bool color = true) : base(width, height, color)
|
||||
{
|
||||
_titleLabel = new Label(Title);
|
||||
ContentPanel = new Panel {BackColor = contentBack};
|
||||
ActualSize = new Size(width, height);
|
||||
Controls.Add(ContentPanel);
|
||||
Controls.Add(_titleLabel);
|
||||
WindowResize += (screen, args) => CalculatePosition();
|
||||
((Control) this).Resize += (caller, args) => CalculatePosition();
|
||||
CalculatePosition(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The title to display at the top of the console
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set
|
||||
{
|
||||
if (_title != value && !string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
_title = value;
|
||||
CalculatePosition(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The actual size of this control. The "Size" property is assigned automatically
|
||||
/// </summary>
|
||||
public Size ActualSize
|
||||
{
|
||||
get => _actualSize;
|
||||
set
|
||||
{
|
||||
if (_actualSize != value)
|
||||
{
|
||||
_actualSize = value;
|
||||
CalculatePosition(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Size variable, Title and ContentPanel position/size
|
||||
/// </summary>
|
||||
/// <param name="initial">Whether this is the initial calculation</param>
|
||||
public void CalculatePosition(bool initial = false)
|
||||
{
|
||||
if (!_resizing)
|
||||
{
|
||||
_resizing = true;
|
||||
Size = new Size(Console.WindowWidth, Console.WindowHeight - 1);
|
||||
_titleLabel.Content = Title + Environment.NewLine + new string(SpecialChars.OneLineSimple.LeftRight, Console.WindowWidth);
|
||||
ContentPanel.Size = ActualSize;
|
||||
ContentPanel.Point = new Point((Console.WindowWidth - ActualSize.Width) / 2,
|
||||
(Console.WindowHeight - ActualSize.Height) / 2);
|
||||
if (!initial)
|
||||
{
|
||||
Console.Clear();
|
||||
DiffDraw.Draw(Color, true);
|
||||
}
|
||||
_resizing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -10,13 +10,22 @@ namespace CC_Functions.Commandline.TUI
|
||||
public class CheckBox : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The text inside this checkbox
|
||||
/// Called when the state of this checkbox is changed
|
||||
/// </summary>
|
||||
public string Content;
|
||||
/// <param name="screen">The current screen instance</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnCheckedChanged(Screen screen, EventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the box is checked
|
||||
/// </summary>
|
||||
public bool Checked = false;
|
||||
public bool Checked;
|
||||
|
||||
/// <summary>
|
||||
/// The text inside this checkbox
|
||||
/// </summary>
|
||||
public string Content;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new checkbox
|
||||
/// </summary>
|
||||
@ -43,6 +52,9 @@ namespace CC_Functions.Commandline.TUI
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
@ -63,15 +75,6 @@ namespace CC_Functions.Commandline.TUI
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the state of this checkbox is changed
|
||||
/// </summary>
|
||||
/// <param name="screen">The current screen instance</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnCheckedChanged(Screen screen, EventArgs e);
|
||||
/// <summary>
|
||||
/// Called when the state of this checkbox is changed
|
||||
/// </summary>
|
||||
|
@ -8,23 +8,39 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public abstract class Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when [enter] is pressed while the control is selected
|
||||
/// </summary>
|
||||
/// <param name="screen">An instance of the calling screen</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnClick(Screen screen, EventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the control is selected and unknown input is given
|
||||
/// </summary>
|
||||
/// <param name="screen">An instance of the calling screen</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnInput(Screen screen, InputEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the controls Size property is changed
|
||||
/// </summary>
|
||||
/// <param name="caller">The calling control</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnResize(Control caller, EventArgs e);
|
||||
/// <summary>
|
||||
/// Called when the controls Size property is changed
|
||||
/// </summary>
|
||||
public event OnResize Resize;
|
||||
private Point _point;
|
||||
|
||||
private Size _size;
|
||||
|
||||
/// <summary>
|
||||
/// Renders the control
|
||||
/// Whether the control can be interacted with
|
||||
/// </summary>
|
||||
/// <returns>The rendered pixels</returns>
|
||||
public abstract Pixel[,] Render();
|
||||
public bool Enabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the control should be rendered
|
||||
/// </summary>
|
||||
public bool Visible = true;
|
||||
|
||||
/// <summary>
|
||||
/// The size of the control
|
||||
/// </summary>
|
||||
@ -40,51 +56,53 @@ namespace CC_Functions.Commandline.TUI
|
||||
}
|
||||
get => _size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The position of this control
|
||||
/// </summary>
|
||||
public Point Point
|
||||
{
|
||||
get => _point;
|
||||
set => _point = value;
|
||||
}
|
||||
public Point Point { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The foreground color for this control
|
||||
/// </summary>
|
||||
public ConsoleColor ForeColor { get; set; } = Console.ForegroundColor;
|
||||
|
||||
/// <summary>
|
||||
/// The background color for this control
|
||||
/// </summary>
|
||||
public ConsoleColor BackColor { get; set; } = Console.BackgroundColor;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the control can be selected
|
||||
/// </summary>
|
||||
public abstract bool Selectable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when [enter] is pressed while the control is selected
|
||||
/// Whether the object is selected. Used internally and for drawing
|
||||
/// </summary>
|
||||
/// <param name="screen">An instance of the calling screen</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnClick(Screen screen, EventArgs e);
|
||||
public bool Selected { get; internal set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the controls Size property is changed
|
||||
/// </summary>
|
||||
public event OnResize Resize;
|
||||
|
||||
/// <summary>
|
||||
/// Renders the control
|
||||
/// </summary>
|
||||
/// <returns>The rendered pixels</returns>
|
||||
public abstract Pixel[,] Render();
|
||||
|
||||
/// <summary>
|
||||
/// Called when [enter] is pressed while the control is selected
|
||||
/// </summary>
|
||||
public event OnClick Click;
|
||||
/// <summary>
|
||||
/// Called when the control is selected and unknown input is given
|
||||
/// </summary>
|
||||
/// <param name="screen">An instance of the calling screen</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnInput(Screen screen, InputEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the control is selected and unknown input is given
|
||||
/// </summary>
|
||||
public event OnInput Input;
|
||||
/// <summary>
|
||||
/// Whether the object is selected. Used internally and for drawing
|
||||
/// </summary>
|
||||
public bool Selected { get; internal set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes click events
|
||||
/// </summary>
|
||||
@ -93,6 +111,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
Click?.Invoke(screen, new EventArgs());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes input events
|
||||
/// </summary>
|
||||
@ -102,13 +121,5 @@ namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
Input?.Invoke(screen, new InputEventArgs(info));
|
||||
}
|
||||
/// <summary>
|
||||
/// Whether the control should be rendered
|
||||
/// </summary>
|
||||
public bool Visible = true;
|
||||
/// <summary>
|
||||
/// Whether the control can be interacted with
|
||||
/// </summary>
|
||||
public bool Enabled = true;
|
||||
}
|
||||
}
|
@ -7,15 +7,15 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class InputEventArgs : EventArgs
|
||||
{
|
||||
private readonly ConsoleKeyInfo _info;
|
||||
/// <summary>
|
||||
/// The inputs data
|
||||
/// </summary>
|
||||
public ConsoleKeyInfo Info => _info;
|
||||
/// <summary>
|
||||
/// Generates new arguments
|
||||
/// </summary>
|
||||
/// <param name="info">The input data</param>
|
||||
public InputEventArgs(ConsoleKeyInfo info) => _info = info;
|
||||
public InputEventArgs(ConsoleKeyInfo info) => Info = info;
|
||||
|
||||
/// <summary>
|
||||
/// The inputs data
|
||||
/// </summary>
|
||||
public ConsoleKeyInfo Info { get; }
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using System.Drawing;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -8,15 +8,40 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class Label : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The text inside this label
|
||||
/// </summary>
|
||||
public string Content;
|
||||
private string _content;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new label
|
||||
/// </summary>
|
||||
/// <param name="content">The text inside this label</param>
|
||||
public Label(string content) => Content = content;
|
||||
public Label(string content)
|
||||
{
|
||||
_content = "";
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// The text inside this label
|
||||
/// </summary>
|
||||
public string Content
|
||||
{
|
||||
get => _content;
|
||||
set
|
||||
{
|
||||
if (_content != value)
|
||||
{
|
||||
_content = value;
|
||||
char[,] inp = Content.ToNdArray2D();
|
||||
int w = inp.GetLength(1);
|
||||
int h = inp.GetLength(0);
|
||||
Size = new Size(w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
@ -27,10 +52,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
output[x, y] = new Pixel(BackColor, ForeColor, inp[x, y]);
|
||||
Size = new Size(w, h);
|
||||
return output;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = false;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -9,11 +9,18 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class Panel : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable to draw a simple border around this control
|
||||
/// </summary>
|
||||
public bool Border = true;
|
||||
/// <summary>
|
||||
/// The controls inside this panel
|
||||
/// </summary>
|
||||
public List<Control> Controls = new List<Control>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Renders the control and all contained controls
|
||||
/// </summary>
|
||||
@ -22,18 +29,21 @@ namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
Pixel[,] tmp = new Pixel[Size.Height, Size.Width];
|
||||
tmp.Populate(new Pixel(BackColor, ForeColor, SpecialChars.Empty));
|
||||
foreach (Control control in Controls)
|
||||
if (Border)
|
||||
{
|
||||
for (int i = 0; i < Size.Width; i++) tmp[Size.Height - 1, i] = new Pixel(BackColor, ForeColor, SpecialChars.OneLineSimple.LeftRight);
|
||||
for (int i = 0; i < Size.Height; i++) tmp[i, Size.Width - 1] = new Pixel(BackColor, ForeColor, SpecialChars.OneLineSimple.UpDown);
|
||||
tmp[Size.Height - 1, Size.Width - 1] = new Pixel(BackColor, ForeColor, '┘');
|
||||
}
|
||||
foreach (Control control in Controls)
|
||||
if (control.Visible)
|
||||
{
|
||||
Pixel[,] render = control.Render();
|
||||
render.CopyTo(tmp, control.Point);
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Recursively enumerates all controls
|
||||
/// </summary>
|
||||
|
@ -8,29 +8,63 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class Pixel
|
||||
{
|
||||
private sealed class ColorContentEqualityComparer : IEqualityComparer<Pixel>
|
||||
public static readonly Pixel Empty = new Pixel();
|
||||
|
||||
/// <summary>
|
||||
/// This pixels background color
|
||||
/// </summary>
|
||||
public ConsoleColor BackColor;
|
||||
|
||||
/// <summary>
|
||||
/// This pixels content character
|
||||
/// </summary>
|
||||
public char Content;
|
||||
|
||||
/// <summary>
|
||||
/// This pixels foregound color
|
||||
/// </summary>
|
||||
public ConsoleColor ForeColor;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
/// <param name="backColor">The background color</param>
|
||||
/// <param name="foreColor">The foreground color</param>
|
||||
/// <param name="content">The new content</param>
|
||||
public Pixel(ConsoleColor backColor, ConsoleColor foreColor, char content)
|
||||
{
|
||||
public bool Equals(Pixel x, Pixel y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.GetHashCode().Equals(y.GetHashCode());
|
||||
BackColor = backColor;
|
||||
ForeColor = foreColor;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public int GetHashCode(Pixel obj) => obj.GetHashCode();
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
/// <param name="content">The content for this pixel</param>
|
||||
public Pixel(char content) : this(Console.BackgroundColor, Console.ForegroundColor, content)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
public Pixel() : this(' ')
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this in functions that require equality comparers
|
||||
/// </summary>
|
||||
public static IEqualityComparer<Pixel> ColorContentComparer { get; } = new ColorContentEqualityComparer();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this is equal to another pixel
|
||||
/// </summary>
|
||||
/// <param name="other">The other pixel to compare</param>
|
||||
/// <returns>Whether they are equal</returns>
|
||||
protected bool Equals(Pixel other) => ColorContentComparer.Equals(this, other);
|
||||
|
||||
/// <summary>
|
||||
/// Whether this is equal to another object
|
||||
/// </summary>
|
||||
@ -48,62 +82,42 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// Generates an integer for comparing this object
|
||||
/// </summary>
|
||||
/// <returns>The generated hash</returns>
|
||||
public override int GetHashCode() => HashCode.Combine((int) BackColor, (int) ForeColor, Content);
|
||||
/// <summary>
|
||||
/// This pixels background color
|
||||
/// </summary>
|
||||
public ConsoleColor BackColor;
|
||||
/// <summary>
|
||||
/// This pixels foregound color
|
||||
/// </summary>
|
||||
public ConsoleColor ForeColor;
|
||||
/// <summary>
|
||||
/// This pixels content character
|
||||
/// </summary>
|
||||
public char Content;
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
/// <param name="backColor">The background color</param>
|
||||
/// <param name="foreColor">The foreground color</param>
|
||||
/// <param name="content">The new content</param>
|
||||
public Pixel(ConsoleColor backColor, ConsoleColor foreColor, char content)
|
||||
{
|
||||
BackColor = backColor;
|
||||
ForeColor = foreColor;
|
||||
Content = content;
|
||||
}
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
/// <param name="content">The content for this pixel</param>
|
||||
public Pixel(char content) : this(Console.BackgroundColor, Console.ForegroundColor, content)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Generates a new pixel
|
||||
/// </summary>
|
||||
public Pixel() : this(' ')
|
||||
{
|
||||
}
|
||||
public override int GetHashCode() => HashCode.Combine(BackColor, ForeColor, Content);
|
||||
|
||||
/// <summary>
|
||||
/// Whether two pixels are equal
|
||||
/// </summary>
|
||||
/// <param name="a">First pixel to compare</param>
|
||||
/// <param name="b">Second pixel to compare</param>
|
||||
/// <returns>Whether they are equal</returns>
|
||||
public static bool operator ==(Pixel a, Pixel b) => a.Equals(b);
|
||||
public static bool operator ==(Pixel a, Pixel b) => !ReferenceEquals(a, null) && a.Equals(b);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to pixels are not equal
|
||||
/// </summary>
|
||||
/// <param name="a">First pixel to compare</param>
|
||||
/// <param name="b">Second pixel to compare</param>
|
||||
/// <returns>Whether they are not equal</returns>
|
||||
public static bool operator !=(Pixel a, Pixel b) => !a.Equals(b);
|
||||
public static bool operator !=(Pixel a, Pixel b) => !(a == b);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content of this pixel
|
||||
/// </summary>
|
||||
/// <returns>The content of this pixel</returns>
|
||||
public override string ToString() => Content.ToString();
|
||||
|
||||
private sealed class ColorContentEqualityComparer : IEqualityComparer<Pixel>
|
||||
{
|
||||
public bool Equals(Pixel x, Pixel y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return true;
|
||||
if (ReferenceEquals(x, null)) return false;
|
||||
if (ReferenceEquals(y, null)) return false;
|
||||
if (x.GetType() != y.GetType()) return false;
|
||||
return x.GetHashCode().Equals(y.GetHashCode());
|
||||
}
|
||||
|
||||
public int GetHashCode(Pixel obj) => obj.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
@ -9,16 +9,66 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class Screen : Panel
|
||||
{
|
||||
/// <summary>
|
||||
/// Called if Escape is pressed, use this for flow control
|
||||
/// </summary>
|
||||
/// <param name="screen">This instance of the screen class</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnClose(Screen screen, EventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the selected control is changed
|
||||
/// </summary>
|
||||
/// <param name="screen">This instance of the screen class</param>
|
||||
/// <param name="args">Args</param>
|
||||
public delegate void OnTabChanged(Screen screen, EventArgs args);
|
||||
|
||||
/// <summary>
|
||||
/// Called by ReadInput if a change in the window size is detected. Use this for positioning
|
||||
/// </summary>
|
||||
/// <param name="screen">This instance of the screen class</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnWindowResize(Screen screen, EventArgs e);
|
||||
|
||||
private bool _color;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to output in color. Recommended for most terminals, might cause slowdowns in others
|
||||
/// </summary>
|
||||
public readonly bool Color;
|
||||
public bool Color
|
||||
{
|
||||
get => _color;
|
||||
set
|
||||
{
|
||||
if (_color != value)
|
||||
{
|
||||
_color = value;
|
||||
DiffDraw.Draw(_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current index of the tab-selected control in an array of selectable controls
|
||||
/// </summary>
|
||||
public int TabPoint = 0;
|
||||
private int _wndWidth = Console.WindowWidth;
|
||||
public int TabPoint
|
||||
{
|
||||
get => _tabPoint;
|
||||
set
|
||||
{
|
||||
if (_tabPoint != value)
|
||||
{
|
||||
_tabPoint = value;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _wndHeight = Console.WindowHeight;
|
||||
private int _wndWidth = Console.WindowWidth;
|
||||
|
||||
private int _tabPoint;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a screen object. Multiple can be instantiated but drawing one overrides others. Use panels for that
|
||||
/// </summary>
|
||||
@ -28,6 +78,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
public Screen(int width, int height, bool color = true)
|
||||
{
|
||||
Color = color;
|
||||
Border = false;
|
||||
Resize(width, height);
|
||||
Tab();
|
||||
}
|
||||
@ -49,6 +100,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <returns>The new state of the screen</returns>
|
||||
public new Pixel[,] Render()
|
||||
{
|
||||
FixSelection();
|
||||
Pixel[,] tmp = base.Render();
|
||||
DiffDraw.Clear(tmp);
|
||||
DiffDraw.Draw(Color);
|
||||
@ -58,7 +110,10 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// <summary>
|
||||
/// Reads input from Console and calls according functions
|
||||
/// </summary>
|
||||
/// <param name="canRedraw">Set to false to prevent redrawing if the screen should be updated. You can Render manually in that case</param>
|
||||
/// <param name="canRedraw">
|
||||
/// Set to false to prevent redrawing if the screen should be updated. You can Render manually in
|
||||
/// that case
|
||||
/// </param>
|
||||
public void ReadInput(bool canRedraw = true)
|
||||
{
|
||||
bool render = false;
|
||||
@ -70,26 +125,22 @@ namespace CC_Functions.Commandline.TUI
|
||||
switch (input.Key)
|
||||
{
|
||||
case ConsoleKey.Tab:
|
||||
Tab(selectable, (input.Modifiers & ConsoleModifiers.Shift) != 0);
|
||||
Tab(selectable, (input.Modifiers & ConsoleModifiers.Shift) == 0);
|
||||
break;
|
||||
case ConsoleKey.Enter:
|
||||
if (selectable.Any() && selectable.Length >= TabPoint && selectable[TabPoint].Enabled)
|
||||
{
|
||||
selectable[TabPoint].InvokeClick(this);
|
||||
render = true;
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.Escape:
|
||||
Close?.Invoke(this, new EventArgs());
|
||||
break;
|
||||
default:
|
||||
if (selectable.Any() && selectable.Length >= TabPoint && selectable[TabPoint].Enabled)
|
||||
{
|
||||
selectable[TabPoint].InvokeInput(this, input);
|
||||
render = true;
|
||||
}
|
||||
InvokeInput(this, input);
|
||||
break;
|
||||
}
|
||||
render = true;
|
||||
}
|
||||
if (_wndWidth != Console.WindowWidth || _wndHeight != Console.WindowHeight)
|
||||
{
|
||||
@ -100,7 +151,10 @@ namespace CC_Functions.Commandline.TUI
|
||||
}
|
||||
if (canRedraw && render)
|
||||
Render();
|
||||
else
|
||||
FixSelection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increases the TabPoint or reverts back to 0 if at the end of selectables
|
||||
/// </summary>
|
||||
@ -111,6 +165,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
Control[] selectable = controls.Where(s => s.Selectable).ToArray();
|
||||
Tab(selectable, positive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increases the TabPoint or reverts back to 0 if at the end of selectables
|
||||
/// </summary>
|
||||
@ -130,30 +185,37 @@ namespace CC_Functions.Commandline.TUI
|
||||
TabPoint--;
|
||||
if (TabPoint < 0) TabPoint = selectable.Length - 1;
|
||||
}
|
||||
FixSelection(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void FixSelection(bool draw = false)
|
||||
{
|
||||
Control[] controls = EnumerateRecursive();
|
||||
Control[] selectable = controls.Where(s => s.Selectable).ToArray();
|
||||
if (selectable.Any())
|
||||
{
|
||||
foreach (Control control in selectable) control.Selected = false;
|
||||
selectable[TabPoint].Selected = true;
|
||||
TabChanged?.Invoke(this, new EventArgs());
|
||||
if (draw)
|
||||
Render();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Called if Escape is pressed, use this for flow control
|
||||
/// </summary>
|
||||
/// <param name="screen">This instance of the screen class</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnClose(Screen screen, EventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called if Escape is pressed, use this for flow control
|
||||
/// </summary>
|
||||
public event OnClose Close;
|
||||
/// <summary>
|
||||
/// Called by ReadInput if a change in the window size is detected. Use this for positioning
|
||||
/// </summary>
|
||||
/// <param name="screen">This instance of the screen class</param>
|
||||
/// <param name="e">Args</param>
|
||||
public delegate void OnWindowResize(Screen screen, EventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// Called by ReadInput if a change in the window size is detected. Use this for positioning
|
||||
/// </summary>
|
||||
public event OnWindowResize WindowResize;
|
||||
|
||||
/// <summary>
|
||||
/// Called when the selected control is changed
|
||||
/// </summary>
|
||||
public event OnTabChanged TabChanged;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -8,6 +8,15 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// </summary>
|
||||
public class Slider : Control
|
||||
{
|
||||
private int _maxValue = 10;
|
||||
private int _minValue;
|
||||
private int _value = 5;
|
||||
|
||||
/// <summary>
|
||||
/// The size of steps in this slider
|
||||
/// </summary>
|
||||
public int StepSize = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new slider
|
||||
/// </summary>
|
||||
@ -22,16 +31,19 @@ namespace CC_Functions.Commandline.TUI
|
||||
if (_value < MinValue)
|
||||
_value = MinValue;
|
||||
Value = _value;
|
||||
ValueChanged?.Invoke(screen, new EventArgs());
|
||||
break;
|
||||
case ConsoleKey.RightArrow:
|
||||
_value += StepSize;
|
||||
if (_value > MaxValue)
|
||||
_value = MaxValue;
|
||||
Value = _value;
|
||||
ValueChanged?.Invoke(screen, new EventArgs());
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum value for this slider
|
||||
/// </summary>
|
||||
@ -41,12 +53,14 @@ namespace CC_Functions.Commandline.TUI
|
||||
get => _maxValue;
|
||||
set
|
||||
{
|
||||
if (value > MinValue && value >= Value)
|
||||
if (value >= MinValue && value >= Value)
|
||||
_maxValue = value;
|
||||
else
|
||||
throw new ArgumentOutOfRangeException("MaxValue must be larger than MinValue and equal to or larger than Value");
|
||||
throw new ArgumentOutOfRangeException(
|
||||
"MaxValue must be larger than MinValue and equal to or larger than Value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The minimal value for this slider
|
||||
/// </summary>
|
||||
@ -56,12 +70,14 @@ namespace CC_Functions.Commandline.TUI
|
||||
get => _minValue;
|
||||
set
|
||||
{
|
||||
if (value < MaxValue && value <= Value)
|
||||
if (value <= MaxValue && value <= Value)
|
||||
_minValue = value;
|
||||
else
|
||||
throw new ArgumentOutOfRangeException("MaxValue must be larger than MinValue and equal to or smaller than Value");
|
||||
throw new ArgumentOutOfRangeException(
|
||||
"MaxValue must be larger than MinValue and equal to or smaller than Value");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current value of this slider
|
||||
/// </summary>
|
||||
@ -77,30 +93,33 @@ namespace CC_Functions.Commandline.TUI
|
||||
throw new ArgumentOutOfRangeException("Value must be between MinValue and MaxValue");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The size of steps in this slider
|
||||
/// </summary>
|
||||
public int StepSize = 1;
|
||||
private int _value = 5;
|
||||
private int _maxValue = 10;
|
||||
private int _minValue = 0;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
int delta = MaxValue - MinValue;
|
||||
int litValLen = Math.Max(MaxValue.ToString().Length, MinValue.ToString().Length);
|
||||
int prevpts = Math.Max((Value - MinValue) * Size.Width / delta - litValLen - 2, 0);
|
||||
int prevpts = Math.Max((Value - MinValue) * Size.Width / Math.Max(delta, 1) - litValLen - 2, 0);
|
||||
int postpts = Math.Max(Size.Width - prevpts - litValLen - 2, 0);
|
||||
char[,] rend = $"{new string('=', prevpts)}[{Value.ToString($"D{litValLen}")}]{new string('=', postpts)}".ToNdArray2D();
|
||||
char[,] rend = $"{new string('=', prevpts)}[{Value.ToString($"D{(Value < 0 ? litValLen - 1 : litValLen)}")}]{new string('=', postpts)}"
|
||||
.ToNdArray2D();
|
||||
int f1 = rend.GetLength(0);
|
||||
int f2 = rend.GetLength(1);
|
||||
Pixel[,] output = new Pixel[f1, f2];
|
||||
output.Populate(new Pixel());
|
||||
for (int i = 0; i < f1; i++)
|
||||
for (int j = 0; j < f2; j++) output[i, j] = new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor, rend[i, j]);
|
||||
for (int j = 0; j < f2; j++)
|
||||
output[i, j] = new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor,
|
||||
rend[i, j]);
|
||||
return output;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Called if the selected value of the slider changes
|
||||
/// </summary>
|
||||
public event OnClick ValueChanged;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Commandline.TUI
|
||||
{
|
||||
@ -15,15 +15,12 @@ namespace CC_Functions.Commandline.TUI
|
||||
/// The text inside this textbox
|
||||
/// </summary>
|
||||
public string Content;
|
||||
private string[] Lines
|
||||
{
|
||||
get => Content.Split('\n');
|
||||
set => Content = string.Join('\n', value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The "Cursors" position in this text box
|
||||
/// </summary>
|
||||
public Point Cursor = new Point(0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new text box
|
||||
/// </summary>
|
||||
@ -31,12 +28,19 @@ namespace CC_Functions.Commandline.TUI
|
||||
public TextBox(string content)
|
||||
{
|
||||
Content = content;
|
||||
Input += (screen, args) =>
|
||||
{
|
||||
ProcessInput(args.Info.Key, args.Info);
|
||||
};
|
||||
Input += (screen, args) => { ProcessInput(args.Info.Key, args.Info); };
|
||||
Click += (screen, args) => ProcessInput(ConsoleKey.Enter, new ConsoleKeyInfo());
|
||||
}
|
||||
|
||||
private string[] Lines
|
||||
{
|
||||
get => Content.Split('\n');
|
||||
set => Content = string.Join('\n', value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Function to process input
|
||||
/// </summary>
|
||||
@ -123,7 +127,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
tmp.RemoveAt(Cursor.Y);
|
||||
lines = tmp.ToArray();
|
||||
Cursor.Y--;
|
||||
Cursor.X = tmplen - 1;
|
||||
Cursor.X = tmplen;
|
||||
}
|
||||
}
|
||||
Lines = lines;
|
||||
@ -131,8 +135,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
case ConsoleKey.Enter:
|
||||
if (lines.Length < Size.Height)
|
||||
{
|
||||
tmp = lines.ToList();
|
||||
lines[Cursor.Y] = lines[Cursor.Y].Insert(Cursor.X, "\n");
|
||||
lines[Cursor.Y] = lines[Cursor.Y].Insert(Math.Max(Cursor.X, 0), "\n");
|
||||
Cursor.Y++;
|
||||
Cursor.X = 0;
|
||||
Lines = lines;
|
||||
@ -142,6 +145,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
if (lines[Cursor.Y].Length < Size.Width)
|
||||
{
|
||||
lines[Cursor.Y] = lines[Cursor.Y].Insert(Cursor.X, info.KeyChar.ToString());
|
||||
Cursor.X++;
|
||||
Lines = lines;
|
||||
}
|
||||
break;
|
||||
@ -152,7 +156,7 @@ namespace CC_Functions.Commandline.TUI
|
||||
public override Pixel[,] Render()
|
||||
{
|
||||
char[,] inp1 = Content.ToNdArray2D();
|
||||
inp1 = inp1.Resize(Size.Height, Size.Width - 2);
|
||||
inp1 = inp1.Resize(Size.Height, Size.Width - 2, SpecialChars.Empty);
|
||||
char[,] inp = new char[Size.Width, Size.Height];
|
||||
inp.Populate(SpecialChars.Empty);
|
||||
for (int i = 0; i < Size.Height; i++)
|
||||
@ -160,18 +164,17 @@ namespace CC_Functions.Commandline.TUI
|
||||
inp[0, i] = '[';
|
||||
inp[Size.Width - 1, i] = ']';
|
||||
}
|
||||
if (Lines.Length < Size.Width)
|
||||
for (int i = 0; i < Size.Width; i++) inp[i, Size.Height - 1] = '.';
|
||||
inp1.Rotate().CopyTo(inp, new Point(0, 1));
|
||||
if (Selected)
|
||||
inp[Cursor.X + 1, Cursor.Y] = '▒';
|
||||
inp[Math.Max(Cursor.X + 1, 1), Cursor.Y] = '▒';
|
||||
Pixel[,] output = new Pixel[Size.Height, Size.Width];
|
||||
output.Populate(new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor, SpecialChars.Empty));
|
||||
for (int x = 0; x < Size.Width; x++)
|
||||
for (int y = 0; y < Size.Height; y++)
|
||||
output[y, x] = new Pixel(Selected ? ForeColor : BackColor, Selected ? BackColor : ForeColor, inp[x, y]);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Selectable { get; } = true;
|
||||
}
|
||||
}
|
@ -14,7 +14,8 @@ namespace CC_Functions.Commandline
|
||||
public static class TableParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses the enumerable to a table using with the specified headers and transformed to strings with the specified selector
|
||||
/// Parses the enumerable to a table using with the specified headers and transformed to strings with the specified
|
||||
/// selector
|
||||
/// </summary>
|
||||
/// <param name="values">The values to display</param>
|
||||
/// <param name="columnHeaders">The headers for columns</param>
|
||||
@ -23,6 +24,7 @@ namespace CC_Functions.Commandline
|
||||
/// <returns>The generated table</returns>
|
||||
public static string ToStringTable<T>(this IEnumerable<T> values, string[] columnHeaders,
|
||||
params Func<T, object>[] valueSelectors) => ToStringTable(values.ToArray(), columnHeaders, valueSelectors);
|
||||
|
||||
/// <summary>
|
||||
/// Parses the array to a table using with the specified headers and transformed to strings with the specified selector
|
||||
/// </summary>
|
||||
@ -53,6 +55,7 @@ namespace CC_Functions.Commandline
|
||||
|
||||
return ToStringTable(arrValues);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the array to a table
|
||||
/// </summary>
|
||||
@ -104,6 +107,7 @@ namespace CC_Functions.Commandline
|
||||
|
||||
return maxColumnsWidth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the enumerable to a table, transformed to strings with the specified selector
|
||||
/// </summary>
|
||||
|
@ -2,7 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace CC_Functions.Misc
|
||||
namespace CC_Functions.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension functions to work with 1D and 2D arrays
|
||||
@ -23,6 +23,7 @@ namespace CC_Functions.Misc
|
||||
Array.Resize(ref output, elements);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies and resizes the array
|
||||
/// </summary>
|
||||
@ -43,6 +44,7 @@ namespace CC_Functions.Misc
|
||||
newArray[i, j] = original[i, j];
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to a 2d char array using newlines
|
||||
/// </summary>
|
||||
@ -64,15 +66,18 @@ namespace CC_Functions.Misc
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears and fills the array with the specified value
|
||||
/// </summary>
|
||||
/// <param name="arr">The array to populate</param>
|
||||
/// <param name="value">The value to copy to the array, defaults to the default value (usually null)</param>
|
||||
/// <typeparam name="T">The type of elements in the array</typeparam>
|
||||
public static void Populate<T>(this T[] arr, T value = default) {
|
||||
public static void Populate<T>(this T[] arr, T value = default)
|
||||
{
|
||||
for (int i = 0; i < arr.Length; i++) arr[i] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears and fills the array with the specified value
|
||||
/// </summary>
|
||||
@ -84,8 +89,10 @@ namespace CC_Functions.Misc
|
||||
int w = arr.GetLength(0);
|
||||
int h = arr.GetLength(1);
|
||||
for (int i = 0; i < w; i++)
|
||||
for (int j = 0; j < h; j++) arr[i, j] = value;
|
||||
for (int j = 0; j < h; j++)
|
||||
arr[i, j] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the content of a 2D array to another with offset
|
||||
/// </summary>
|
||||
@ -101,10 +108,12 @@ namespace CC_Functions.Misc
|
||||
int mh = target.GetLength(0);
|
||||
int ow = offset.X;
|
||||
int oh = offset.Y;
|
||||
if (oh >= 0 && ow >= 0 && mw >= 0 && mh >= 0 && w >= 0 && h >= 0)
|
||||
for (int x = ow; x < Math.Min(mw, w + ow); x++)
|
||||
for (int y = oh; y < Math.Min(mh, h + oh); y++)
|
||||
target[y, x] = arr[y - oh, x - ow];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies and rotates the 2d array (row->column, column->row)
|
||||
/// </summary>
|
||||
@ -117,7 +126,8 @@ namespace CC_Functions.Misc
|
||||
int h = arr.GetLength(1);
|
||||
T[,] target = new T[h, w];
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++) target[y, x] = arr[x, y];
|
||||
for (int y = 0; y < h; y++)
|
||||
target[y, x] = arr[x, y];
|
||||
return target;
|
||||
}
|
||||
}
|
28
Core/Core.csproj
Normal file
28
Core/Core.csproj
Normal file
@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>CC_Functions.Core</RootNamespace>
|
||||
<AssemblyName>CC_Functions.Core</AssemblyName>
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.Core</PackageId>
|
||||
<Title>CC-Functions.Core</Title>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>Random pieces of code without external dependencies. Used in other CC_Functions packages</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<VersionSuffix>0.0</VersionSuffix>
|
||||
<PackageVersion>1.1.$(VersionSuffix)</PackageVersion>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DocumentationFile>bin\Debug\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\Release\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
</Project>
|
255
Core/GenericExtensions.cs
Normal file
255
Core/GenericExtensions.cs
Normal file
@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace CC_Functions.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for various types
|
||||
/// </summary>
|
||||
public static class GenericExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an element from the dictionary or adds the default
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to get from</param>
|
||||
/// <param name="key">The key to check</param>
|
||||
/// <param name="def">The default value to place</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
/// <returns>The element at the key</returns>
|
||||
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue def = default)
|
||||
{
|
||||
if (!dict.ContainsKey(key))
|
||||
dict[key] = def;
|
||||
return dict[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets an element and returns it
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to set in</param>
|
||||
/// <param name="key">The key to set at</param>
|
||||
/// <param name="val">The value to place</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
/// <returns>The value that was placed</returns>
|
||||
public static TValue Set<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue val = default)
|
||||
{
|
||||
dict[key] = val;
|
||||
return dict[key];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to cast an object
|
||||
/// </summary>
|
||||
/// <param name="o">The object to try to parse</param>
|
||||
/// <param name="parsed">The parsed object (if successful) or the default (usually null)</param>
|
||||
/// <typeparam name="T">The type to cast to</typeparam>
|
||||
/// <returns>Whether the cast was successful</returns>
|
||||
public static bool TryCast<T>(this object o, out T parsed)
|
||||
{
|
||||
try
|
||||
{
|
||||
parsed = (T) o;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
parsed = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a function that transforms an object in-line
|
||||
/// </summary>
|
||||
/// <param name="self">The object to run on</param>
|
||||
/// <param name="func">The function to run</param>
|
||||
/// <typeparam name="TIn">The input type</typeparam>
|
||||
/// <typeparam name="TOut">The output type</typeparam>
|
||||
/// <returns></returns>
|
||||
public static TOut SelectO<TIn, TOut>(this TIn self, Func<TIn, TOut> func) => func.Invoke(self);
|
||||
|
||||
/// <summary>
|
||||
/// Runs a function under a condition in-line (equal to if)
|
||||
/// </summary>
|
||||
/// <param name="condition">The condition to check</param>
|
||||
/// <param name="func">The function to run</param>
|
||||
public static void RunIf(bool condition, Action func)
|
||||
{
|
||||
if (condition)
|
||||
func();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a string to a value of an enum
|
||||
/// </summary>
|
||||
/// <param name="value">The string to parse</param>
|
||||
/// <typeparam name="TEnum">The enum type (MUST be an enum)</typeparam>
|
||||
/// <returns>The element</returns>
|
||||
public static TEnum ParseToEnum<TEnum>(string value) => (TEnum) Enum.Parse(typeof(TEnum),
|
||||
Enum.GetNames(typeof(TEnum)).First(s => s.ToLower() == value.ToLower()));
|
||||
|
||||
/// <summary>
|
||||
/// Parses a string to a nullable bool (defaults to null if parse fails)
|
||||
/// </summary>
|
||||
/// <param name="value">The st string to parse</param>
|
||||
/// <returns>The output nullable bool</returns>
|
||||
public static bool? ParseBool(string value) =>
|
||||
bool.TryParse(value, out bool tmp) ? (bool?) tmp : null;
|
||||
|
||||
/// <summary>
|
||||
/// AND operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool And(this bool? left, bool? right) => left.True() && right.True();
|
||||
|
||||
/// <summary>
|
||||
/// OR operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool Or(this bool? left, bool? right) => left.True() || right.True();
|
||||
|
||||
/// <summary>
|
||||
/// XOR operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool Xor(this bool? left, bool? right) => left.Or(right) && !left.And(right);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is true (null->false)
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is true</returns>
|
||||
public static bool True(this bool? self) => self == true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is false (null->false)
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is false</returns>
|
||||
public static bool False(this bool? self) => self == false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is null
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is null</returns>
|
||||
public static bool Null(this bool? self) => self == null;
|
||||
|
||||
/// <summary>
|
||||
/// Removes an element from a dictionary by its index (not key)
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to remove from</param>
|
||||
/// <param name="index">The index of the value</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
public static void RemoveAt<TKey, TValue>(this Dictionary<TKey, TValue> dict, int index) =>
|
||||
dict.Remove(dict.Keys.ToArray()[index]);
|
||||
|
||||
/// <summary>
|
||||
/// "Unshorten" (follow) an URL
|
||||
/// </summary>
|
||||
/// <param name="self">The URL to unshorten</param>
|
||||
/// <returns>The unshortened URL</returns>
|
||||
public static Uri Unshorten(this Uri self)
|
||||
{
|
||||
HttpWebRequest req = (HttpWebRequest) WebRequest.Create(self);
|
||||
req.AllowAutoRedirect = true;
|
||||
req.MaximumAutomaticRedirections = 100;
|
||||
WebResponse resp = req.GetResponse();
|
||||
return resp.ResponseUri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rounds a RectangleF to a Rectangle instead of flooring
|
||||
/// </summary>
|
||||
/// <param name="self">The RectangleF to round</param>
|
||||
/// <returns>The rounded Rectangle</returns>
|
||||
public static Rectangle Round(this RectangleF self) => Rectangle.Round(self);
|
||||
|
||||
/// <summary>
|
||||
/// Ceilings a RectangleF to a Rectangle instead of flooring
|
||||
/// </summary>
|
||||
/// <param name="self">The RectangleF to ceil (?)</param>
|
||||
/// <returns>The ceiled (?) Rectangle</returns>
|
||||
public static Rectangle Ceiling(this RectangleF self) => Rectangle.Ceiling(self);
|
||||
|
||||
/// <summary>
|
||||
/// Pings an URL to check for availability
|
||||
/// </summary>
|
||||
/// <param name="self">The URL to check</param>
|
||||
/// <returns>Whether the service is online</returns>
|
||||
public static bool Ping(this Uri self)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(self);
|
||||
request.Timeout = 3000;
|
||||
request.AllowAutoRedirect = true;
|
||||
using WebResponse response = request.GetResponse();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a dictionary
|
||||
/// </summary>
|
||||
/// <param name="directory">The dictionary to check</param>
|
||||
/// <returns>The size of the dictionary</returns>
|
||||
public static long GetSize(this DirectoryInfo directory) => IO.GetDirectorySize(directory.FullName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a directory to an archive recursively
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to add to</param>
|
||||
/// <param name="folderPath">The directory to add</param>
|
||||
/// <param name="entryName">The name of the directory in-archive</param>
|
||||
/// <param name="ignoredExtensions">Extensions for files to ignore</param>
|
||||
/// <param name="ignoredPaths">Paths to exclude from adding</param>
|
||||
/// <returns>The new entry</returns>
|
||||
public static ZipArchiveEntry AddDirectory(this ZipArchive archive, string folderPath, string entryName,
|
||||
string[] ignoredExtensions, string[] ignoredPaths)
|
||||
{
|
||||
entryName = entryName.TrimEnd('/');
|
||||
ZipArchiveEntry result = archive.CreateEntry($"{entryName}/");
|
||||
string[] files = Directory.GetFiles(folderPath);
|
||||
foreach (string t in files)
|
||||
if (!ignoredExtensions.Contains(Path.GetExtension(t)) &&
|
||||
!ignoredPaths.Any(s => IO.CheckPathEqual(s, t)))
|
||||
archive.CreateEntryFromFile(t, $"{entryName}/{Path.GetFileName(t)}");
|
||||
string[] dirs = Directory.GetDirectories(folderPath);
|
||||
foreach (string t in dirs)
|
||||
if (!ignoredPaths.Any(s => IO.CheckPathEqual(s, t)))
|
||||
archive.AddDirectory(t, $"{entryName}/{Path.GetFileName(t)}", ignoredExtensions,
|
||||
ignoredPaths);
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the threads cultureInfo properties to InvariantCulture. For testing
|
||||
/// </summary>
|
||||
/// <param name="thread">The thread to modify</param>
|
||||
public static void ForceInvariantCulture(this Thread thread)
|
||||
{
|
||||
thread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
thread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace CC_Functions.Misc
|
||||
namespace CC_Functions.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// IO functions
|
||||
@ -21,6 +21,7 @@ namespace CC_Functions.Misc
|
||||
size += new FileInfo(t).Length;
|
||||
return size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the paths are equivalent (ignores case)
|
||||
/// </summary>
|
156
Core/SpecialChars.cs
Normal file
156
Core/SpecialChars.cs
Normal file
@ -0,0 +1,156 @@
|
||||
namespace CC_Functions.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Characters for use in CC-Functions.CommandLine
|
||||
/// </summary>
|
||||
public static class SpecialChars
|
||||
{
|
||||
/// <summary>
|
||||
/// The space character
|
||||
/// </summary>
|
||||
public const char Empty = ' ';
|
||||
/// <summary>
|
||||
/// Wall with two lines
|
||||
/// </summary>
|
||||
public static class TwoLineSimple
|
||||
{
|
||||
// 1 connectors
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char Up = '║';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char Down = '║';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char Left = '═';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char Right = '═';
|
||||
|
||||
// 2 connectors
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpDown = '║';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char LeftRight = '═';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char DownRight = '╔';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpRight = '╚';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char DownLeft = '╗';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpLeft = '╝';
|
||||
|
||||
// 3 connectors
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpDownLeft = '╣';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpDownRight = '╠';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpLeftRight = '╩';
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char DownLeftRight = '╦';
|
||||
|
||||
// 4 connectors
|
||||
/// <summary>
|
||||
/// Wall with specified points
|
||||
/// </summary>
|
||||
public const char UpDownLeftRight = '╬';
|
||||
}
|
||||
/// <summary>
|
||||
/// Simple line
|
||||
/// </summary>
|
||||
public static class OneLineSimple
|
||||
{
|
||||
// 1 connectors
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char Up = '╵';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char Down = '╷';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char Left = '╴';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char Right = '╶';
|
||||
|
||||
// 2 connectors
|
||||
public const char UpDown = '│';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char LeftRight = '─';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char DownRight = '┌';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpRight = '└';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char DownLeft = '┐';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpLeft = '┘';
|
||||
|
||||
// 3 connectors
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpDownLeft = '┤';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpDownRight = '├';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpLeftRight = '┴';
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char DownLeftRight = '┬';
|
||||
|
||||
// 4 connectors
|
||||
/// <summary>
|
||||
/// Line with specified points
|
||||
/// </summary>
|
||||
public const char UpDownLeftRight = '┼';
|
||||
}
|
||||
}
|
||||
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 J. Fronny
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -49,6 +49,7 @@ namespace CC_Functions.Misc
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts an SHA512-encrypted byte array. Use with <see cref="Encrypt">Encrypt</see>
|
||||
/// </summary>
|
||||
|
@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using CC_Functions.Core;
|
||||
|
||||
namespace CC_Functions.Misc
|
||||
{
|
||||
@ -13,215 +12,6 @@ namespace CC_Functions.Misc
|
||||
/// </summary>
|
||||
public static class GenericExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an element from the dictionary or adds the default
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to get from</param>
|
||||
/// <param name="key">The key to check</param>
|
||||
/// <param name="def">The default value to place</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
/// <returns>The element at the key</returns>
|
||||
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue def = default)
|
||||
{
|
||||
if (!dict.ContainsKey(key))
|
||||
dict[key] = def;
|
||||
return dict[key];
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets an element and returns it
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to set in</param>
|
||||
/// <param name="key">The key to set at</param>
|
||||
/// <param name="val">The value to place</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
/// <returns>The value that was placed</returns>
|
||||
public static TValue Set<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue val = default)
|
||||
{
|
||||
dict[key] = val;
|
||||
return dict[key];
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to cast an object
|
||||
/// </summary>
|
||||
/// <param name="o">The object to try to parse</param>
|
||||
/// <param name="parsed">The parsed object (if successful) or the default (usually null)</param>
|
||||
/// <typeparam name="T">The type to cast to</typeparam>
|
||||
/// <returns>Whether the cast was successful</returns>
|
||||
public static bool TryCast<T>(this object o, out T parsed)
|
||||
{
|
||||
try
|
||||
{
|
||||
parsed = (T) o;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
parsed = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Runs a function that transforms an object in-line
|
||||
/// </summary>
|
||||
/// <param name="self">The object to run on</param>
|
||||
/// <param name="func">The function to run</param>
|
||||
/// <typeparam name="TIn">The input type</typeparam>
|
||||
/// <typeparam name="TOut">The output type</typeparam>
|
||||
/// <returns></returns>
|
||||
public static TOut SelectO<TIn, TOut>(this TIn self, Func<TIn, TOut> func) => func.Invoke(self);
|
||||
/// <summary>
|
||||
/// Runs a function under a condition in-line (equal to if)
|
||||
/// </summary>
|
||||
/// <param name="condition">The condition to check</param>
|
||||
/// <param name="func">The function to run</param>
|
||||
public static void RunIf(bool condition, Action func)
|
||||
{
|
||||
if (condition)
|
||||
func();
|
||||
}
|
||||
/// <summary>
|
||||
/// Parses a string to a value of an enum
|
||||
/// </summary>
|
||||
/// <param name="value">The string to parse</param>
|
||||
/// <typeparam name="TEnum">The enum type (MUST be an enum)</typeparam>
|
||||
/// <returns>The element</returns>
|
||||
public static TEnum ParseToEnum<TEnum>(string value) => (TEnum) Enum.Parse(typeof(TEnum),
|
||||
Enum.GetNames(typeof(TEnum)).First(s => s.ToLower() == value.ToLower()));
|
||||
|
||||
/// <summary>
|
||||
/// Parses a string to a nullable bool (defaults to null if parse fails)
|
||||
/// </summary>
|
||||
/// <param name="value">The st string to parse</param>
|
||||
/// <returns>The output nullable bool</returns>
|
||||
public static bool? ParseBool(string value) =>
|
||||
bool.TryParse(value, out bool tmp) ? (bool?)tmp : null;
|
||||
/// <summary>
|
||||
/// AND operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool And(this bool? left, bool? right) => left.True() && right.True();
|
||||
/// <summary>
|
||||
/// OR operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool Or(this bool? left, bool? right) => left.True() || right.True();
|
||||
/// <summary>
|
||||
/// XOR operation for nullable bools (uses <see cref="True">True</see>)
|
||||
/// </summary>
|
||||
/// <param name="left">First bool to check</param>
|
||||
/// <param name="right">Second bool to check</param>
|
||||
/// <returns>The operation result</returns>
|
||||
public static bool Xor(this bool? left, bool? right) => left.Or(right) && !left.And(right);
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is true (null->false)
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is true</returns>
|
||||
public static bool True(this bool? self) => self == true;
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is false (null->false)
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is false</returns>
|
||||
public static bool False(this bool? self) => self == false;
|
||||
/// <summary>
|
||||
/// Whether the nullable bool is null
|
||||
/// </summary>
|
||||
/// <param name="self">Value to check</param>
|
||||
/// <returns>Whether it is null</returns>
|
||||
public static bool Null(this bool? self) => self == null;
|
||||
/// <summary>
|
||||
/// Removes an element from a dictionary by its index (not key)
|
||||
/// </summary>
|
||||
/// <param name="dict">The dictionary to remove from</param>
|
||||
/// <param name="index">The index of the value</param>
|
||||
/// <typeparam name="TKey">The key type</typeparam>
|
||||
/// <typeparam name="TValue">The value type</typeparam>
|
||||
public static void RemoveAt<TKey, TValue>(this Dictionary<TKey, TValue> dict, int index) =>
|
||||
dict.Remove(dict.Keys.ToArray()[index]);
|
||||
/// <summary>
|
||||
/// Gets the size of a dictionary
|
||||
/// </summary>
|
||||
/// <param name="directory">The dictionary to check</param>
|
||||
/// <returns>The size of the dictionary</returns>
|
||||
public static long GetSize(this DirectoryInfo directory) => IO.GetDirectorySize(directory.FullName);
|
||||
/// <summary>
|
||||
/// Adds a directory to an archive recursively
|
||||
/// </summary>
|
||||
/// <param name="archive">The archive to add to</param>
|
||||
/// <param name="folderPath">The directory to add</param>
|
||||
/// <param name="entryName">The name of the directory in-archive</param>
|
||||
/// <param name="ignoredExtensions">Extensions for files to ignore</param>
|
||||
/// <param name="ignoredPaths">Paths to exclude from adding</param>
|
||||
/// <returns>The new entry</returns>
|
||||
public static ZipArchiveEntry AddDirectory(this ZipArchive archive, string folderPath, string entryName,
|
||||
string[] ignoredExtensions, string[] ignoredPaths)
|
||||
{
|
||||
entryName = entryName.TrimEnd('/');
|
||||
ZipArchiveEntry result = archive.CreateEntry($"{entryName}/");
|
||||
string[] files = Directory.GetFiles(folderPath);
|
||||
foreach (string t in files)
|
||||
if (!ignoredExtensions.Contains(Path.GetExtension(t)) &&
|
||||
!ignoredPaths.Any(s => IO.CheckPathEqual(s, t)))
|
||||
archive.CreateEntryFromFile(t, $"{entryName}/{Path.GetFileName(t)}");
|
||||
string[] dirs = Directory.GetDirectories(folderPath);
|
||||
foreach (string t in dirs)
|
||||
if (!ignoredPaths.Any(s => IO.CheckPathEqual(s, t)))
|
||||
archive.AddDirectory(t, $"{entryName}/{Path.GetFileName(t)}", ignoredExtensions,
|
||||
ignoredPaths);
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// "Unshorten" (follow) an URL
|
||||
/// </summary>
|
||||
/// <param name="self">The URL to unshorten</param>
|
||||
/// <returns>The unshortened URL</returns>
|
||||
public static Uri Unshorten(this Uri self)
|
||||
{
|
||||
HttpWebRequest req = (HttpWebRequest) WebRequest.Create(self);
|
||||
req.AllowAutoRedirect = true;
|
||||
req.MaximumAutomaticRedirections = 100;
|
||||
WebResponse resp = req.GetResponse();
|
||||
return resp.ResponseUri;
|
||||
}
|
||||
/// <summary>
|
||||
/// Pings an URL to check for availability
|
||||
/// </summary>
|
||||
/// <param name="self">The URL to check</param>
|
||||
/// <returns>Whether the service is online</returns>
|
||||
public static bool Ping(this Uri self)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(self);
|
||||
request.Timeout = 3000;
|
||||
request.AllowAutoRedirect = true;
|
||||
using WebResponse response = request.GetResponse();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Rounds a RectangleF to a Rectangle instead of flooring
|
||||
/// </summary>
|
||||
/// <param name="self">The RectangleF to round</param>
|
||||
/// <returns>The rounded Rectangle</returns>
|
||||
public static Rectangle Round(this RectangleF self) => Rectangle.Round(self);
|
||||
/// <summary>
|
||||
/// Ceilings a RectangleF to a Rectangle instead of flooring
|
||||
/// </summary>
|
||||
/// <param name="self">The RectangleF to ceil (?)</param>
|
||||
/// <returns>The ceiled (?) Rectangle</returns>
|
||||
public static Rectangle Ceiling(this RectangleF self) => Rectangle.Ceiling(self);
|
||||
/// <summary>
|
||||
/// Extension method for <see cref="Crypto">Crypto's</see> Encrypt
|
||||
/// </summary>
|
||||
@ -229,6 +19,7 @@ namespace CC_Functions.Misc
|
||||
/// <param name="key">The key to encrypt with</param>
|
||||
/// <returns>The encrypted data</returns>
|
||||
public static byte[] Encrypt(this byte[] self, byte[] key) => Crypto.Encrypt(self, key);
|
||||
|
||||
/// <summary>
|
||||
/// Extension method for <see cref="Crypto">Crypto's</see> Decrypt
|
||||
/// </summary>
|
||||
|
15
Misc/HID.cs
15
Misc/HID.cs
@ -16,9 +16,10 @@ namespace CC_Functions.Misc
|
||||
/// Whether to force Win32-based operation
|
||||
/// </summary>
|
||||
public static bool ForceWindows = false;
|
||||
|
||||
private static byte[] _fingerPrint;
|
||||
|
||||
private static readonly string HIDClasses = @"Win32_Processor:UniqueId
|
||||
private static readonly string HidClasses = @"Win32_Processor:UniqueId
|
||||
Win32_Processor:ProcessorId
|
||||
Win32_Processor:Name
|
||||
Win32_Processor:Manufacturer
|
||||
@ -33,6 +34,7 @@ Win32_BaseBoard:Manufacturer
|
||||
Win32_BaseBoard:Name
|
||||
Win32_BaseBoard:SerialNumber
|
||||
Win32_NetworkAdapterConfiguration:MACAddress";
|
||||
|
||||
/// <summary>
|
||||
/// The HID for this machine
|
||||
/// </summary>
|
||||
@ -42,9 +44,13 @@ Win32_NetworkAdapterConfiguration:MACAddress";
|
||||
{
|
||||
if (_fingerPrint != null) return _fingerPrint;
|
||||
string fingerprintTmp = "";
|
||||
if (ForceWindows || new [] {PlatformID.Xbox, PlatformID.Win32S, PlatformID.Win32Windows, PlatformID.Win32NT, PlatformID.WinCE}.Contains(Environment.OSVersion.Platform))
|
||||
if (ForceWindows ||
|
||||
new[]
|
||||
{
|
||||
HIDClasses.Split(new[] {"\r\n"}, StringSplitOptions.None).Select(s =>
|
||||
PlatformID.Xbox, PlatformID.Win32S, PlatformID.Win32Windows, PlatformID.Win32NT,
|
||||
PlatformID.WinCE
|
||||
}.Contains(Environment.OSVersion.Platform))
|
||||
HidClasses.Split(new[] {"\r\n"}, StringSplitOptions.None).Select(s =>
|
||||
{
|
||||
if (s.StartsWith("\n"))
|
||||
s = s.Remove(0, 1);
|
||||
@ -65,7 +71,6 @@ Win32_NetworkAdapterConfiguration:MACAddress";
|
||||
Console.WriteLine("Failed to read property");
|
||||
}
|
||||
});
|
||||
}
|
||||
else //Linux implementation. This will not work if you are using Mono on windows or do not have "uname", "lscpu" and "id" available
|
||||
{
|
||||
Process p = new Process
|
||||
@ -99,6 +104,7 @@ Win32_NetworkAdapterConfiguration:MACAddress";
|
||||
return _fingerPrint;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypts data using <see cref="Crypto">Crypto's</see> Encrypt and the HID
|
||||
/// </summary>
|
||||
@ -106,6 +112,7 @@ Win32_NetworkAdapterConfiguration:MACAddress";
|
||||
/// <returns>The encrypted data</returns>
|
||||
public static byte[] EncryptLocal(byte[] unencrypted) =>
|
||||
Crypto.Encrypt(unencrypted, Value);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypts data using <see cref="Crypto">Crypto's</see> Decrypt and the HID
|
||||
/// </summary>
|
||||
|
@ -7,17 +7,17 @@
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.Misc</PackageId>
|
||||
<Title>CC-Functions.Misc</Title>
|
||||
<Authors>CC24</Authors>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>Random pieces of code used across my projects. I do NOT recommend using this in your own project!</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://github.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<VersionSuffix>0.0</VersionSuffix>
|
||||
<PackageVersion>1.1.$(VersionSuffix)</PackageVersion>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DocumentationFile>bin\Debug\Misc.xml</DocumentationFile>
|
||||
@ -29,11 +29,14 @@
|
||||
<EmbeddedResource Include="HIDClasses.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Management" Version="4.7.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
|
||||
<PackageReference Include="System.Management" Version="5.0.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.IO.Compression" Condition="'$(TargetFramework)' == 'net461'" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" Condition="'$(TargetFramework)' == 'net461'" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,13 +0,0 @@
|
||||
namespace CC_Functions.Misc
|
||||
{
|
||||
/// <summary>
|
||||
/// Characters for use in CC-Functions.CommandLine
|
||||
/// </summary>
|
||||
public static class SpecialChars
|
||||
{
|
||||
/// <summary>
|
||||
/// The space character
|
||||
/// </summary>
|
||||
public const char Empty = ' ';
|
||||
}
|
||||
}
|
@ -1,2 +1,6 @@
|
||||
# CC-Functions
|
||||
[![UpTool2](https://img.shields.io/github/v/tag/JFronny/CC-Functions?color=informational&label=UpTool2)](https://jfronny.github.io/home/uptool) [![Nuget](https://img.shields.io/nuget/v/CC-Functions.Misc?label=CC-Functions.Misc)](https://www.nuget.org/packages/CC-Functions.Misc/) [![Nuget](https://img.shields.io/nuget/v/CC-Functions.W32?label=CC-Functions.W32)](https://www.nuget.org/packages/CC-Functions.W32/)
|
||||
[![UpTool2](https://img.shields.io/badge/Get%20it-on%20UpTool2-blue)](https://jfronny.gitlab.io/home/uptool)
|
||||
[![Nuget](https://img.shields.io/nuget/v/CC-Functions.Core?label=CC-Functions.Core)](https://www.nuget.org/packages/CC-Functions.Core/)
|
||||
[![Nuget](https://img.shields.io/nuget/v/CC-Functions.Misc?label=CC-Functions.Misc)](https://www.nuget.org/packages/CC-Functions.Misc/)
|
||||
[![Nuget](https://img.shields.io/nuget/v/CC-Functions.W32?label=CC-Functions.W32)](https://www.nuget.org/packages/CC-Functions.W32/)
|
||||
[![Nuget](https://img.shields.io/nuget/v/CC-Functions.W32?label=CC-Functions.Commandline)](https://www.nuget.org/packages/CC-Functions.Commandline/)
|
||||
|
@ -2,9 +2,8 @@
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CC_Functions.Misc;
|
||||
using CC_Functions.W32.Forms;
|
||||
using CC_Functions.W32.DCDrawer;
|
||||
using CC_Functions.W32.Forms;
|
||||
using CC_Functions.W32.Hooks;
|
||||
using static CC_Functions.W32.Power;
|
||||
|
||||
@ -14,6 +13,8 @@ namespace CC_Functions.W32.Test
|
||||
{
|
||||
private static Wnd32 _tmpWnd32Obj;
|
||||
private static MainForm _mainF;
|
||||
|
||||
private static Wnd32 _wndSelectMouseCurrent;
|
||||
private readonly KeyboardHook _kHook;
|
||||
private readonly MouseHook _mHook;
|
||||
private readonly Label[] _readerLabels;
|
||||
@ -25,7 +26,7 @@ namespace CC_Functions.W32.Test
|
||||
_mainF = this;
|
||||
_tmpWnd32Obj = Wnd32.FromForm(this);
|
||||
#if DEBUG
|
||||
tmpWnd32_obj.MakeOverlay();
|
||||
_tmpWnd32Obj.Overlay = true;
|
||||
#endif
|
||||
set_up_box(power_mode_box, typeof(ShutdownMode));
|
||||
set_up_box(power_reason_box, typeof(ShutdownReason));
|
||||
@ -107,7 +108,7 @@ namespace CC_Functions.W32.Test
|
||||
frm.Controls.Add(pan);
|
||||
Wnd32[] children = TmpWnd.Children;
|
||||
|
||||
void UpdateGUI(Point labelPosition)
|
||||
void UpdateGui(Point labelPosition)
|
||||
{
|
||||
lab.Text = $"{_wndSelectMouseCurrent.Title} ({_wndSelectMouseCurrent.HWnd})";
|
||||
lab.Location = new Point(labelPosition.X + 5, labelPosition.Y + 5);
|
||||
@ -116,11 +117,11 @@ namespace CC_Functions.W32.Test
|
||||
|
||||
void MouseEventHandler(object sender1, MouseEventArgs e1)
|
||||
{
|
||||
Func<Wnd32, bool> checkWnd = (s) => s.Position.Contains(e1.Location);
|
||||
Func<Wnd32, bool> checkWnd = s => s.Position.Contains(e1.Location);
|
||||
if (children.Any(checkWnd))
|
||||
{
|
||||
_wndSelectMouseCurrent = children.First(checkWnd);
|
||||
UpdateGUI(Cursor.Position);
|
||||
UpdateGui(Cursor.Position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +152,7 @@ namespace CC_Functions.W32.Test
|
||||
tmp = children.Length;
|
||||
tmp--;
|
||||
_wndSelectMouseCurrent = children[tmp];
|
||||
UpdateGUI(_wndSelectMouseCurrent.Position.Location);
|
||||
UpdateGui(_wndSelectMouseCurrent.Position.Location);
|
||||
break;
|
||||
case Keys.Down:
|
||||
case Keys.Right:
|
||||
@ -160,7 +161,7 @@ namespace CC_Functions.W32.Test
|
||||
if (tmp == children.Length)
|
||||
tmp = 0;
|
||||
_wndSelectMouseCurrent = children[tmp];
|
||||
UpdateGUI(_wndSelectMouseCurrent.Position.Location);
|
||||
UpdateGui(_wndSelectMouseCurrent.Position.Location);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -172,7 +173,7 @@ namespace CC_Functions.W32.Test
|
||||
pan.MouseMove += MouseEventHandler;
|
||||
lab.MouseMove += MouseEventHandler;
|
||||
frm.KeyDown += KeyEventHandler;
|
||||
UpdateGUI(Cursor.Position);
|
||||
UpdateGui(Cursor.Position);
|
||||
frm.Show();
|
||||
_wndSelectMouseCurrent = frm.GetWnd32();
|
||||
Cursor.Position = Cursor.Position;
|
||||
@ -263,7 +264,6 @@ namespace CC_Functions.W32.Test
|
||||
|
||||
private void Wnd_action_destroy_Click(object sender, EventArgs e) => TmpWnd.Destroy();
|
||||
|
||||
private static Wnd32 _wndSelectMouseCurrent;
|
||||
private void Wnd_select_mouse_Click(object sender, EventArgs e)
|
||||
{
|
||||
WindowState = FormWindowState.Minimized;
|
||||
@ -281,7 +281,7 @@ namespace CC_Functions.W32.Test
|
||||
Panel pan = new Panel {BackColor = Color.Red};
|
||||
frm.Controls.Add(pan);
|
||||
|
||||
void UpdateGUI(Point labelPosition)
|
||||
void UpdateGui(Point labelPosition)
|
||||
{
|
||||
lab.Text = $"{_wndSelectMouseCurrent.Title} ({_wndSelectMouseCurrent.HWnd})";
|
||||
lab.Location = new Point(labelPosition.X + 5, labelPosition.Y + 5);
|
||||
@ -291,7 +291,7 @@ namespace CC_Functions.W32.Test
|
||||
void MouseEventHandler(object sender1, MouseEventArgs e1)
|
||||
{
|
||||
_wndSelectMouseCurrent = Wnd32.AllFromPoint(MousePosition, true).First(s => s != frm.GetWnd32());
|
||||
UpdateGUI(Cursor.Position);
|
||||
UpdateGui(Cursor.Position);
|
||||
}
|
||||
|
||||
void EventHandler(object sender1, EventArgs e1)
|
||||
@ -390,12 +390,12 @@ namespace CC_Functions.W32.Test
|
||||
}
|
||||
|
||||
private static PointF MakePoint(float xPercent, float yPercent) => new PointF(
|
||||
(Screen.PrimaryScreen.Bounds.Width * xPercent) / 100,
|
||||
(Screen.PrimaryScreen.Bounds.Height * yPercent) / 100);
|
||||
Screen.PrimaryScreen.Bounds.Width * xPercent / 100,
|
||||
Screen.PrimaryScreen.Bounds.Height * yPercent / 100);
|
||||
|
||||
private static SizeF MakeSizeY(float xPercent, float yPercent) => new SizeF(
|
||||
(Screen.PrimaryScreen.Bounds.Height * xPercent) / 100,
|
||||
(Screen.PrimaryScreen.Bounds.Height * yPercent) / 100);
|
||||
Screen.PrimaryScreen.Bounds.Height * xPercent / 100,
|
||||
Screen.PrimaryScreen.Bounds.Height * yPercent / 100);
|
||||
|
||||
private void desk_set_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
@ -20,6 +20,8 @@ namespace CC_Functions.W32.DCDrawer
|
||||
Graphics = buffer.Graphics;
|
||||
}
|
||||
|
||||
public Graphics Graphics { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
buffer.Render(drawer.Graphics);
|
||||
@ -27,7 +29,5 @@ namespace CC_Functions.W32.DCDrawer
|
||||
buffer.Dispose();
|
||||
drawer.Dispose();
|
||||
}
|
||||
|
||||
public Graphics Graphics { get; }
|
||||
}
|
||||
}
|
@ -16,11 +16,10 @@ namespace CC_Functions.W32
|
||||
{
|
||||
using (Bitmap bmpTemp =
|
||||
new Bitmap(
|
||||
$@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Microsoft\Windows\Themes\TranscodedWallpaper"))
|
||||
{
|
||||
$@"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\Microsoft\Windows\Themes\TranscodedWallpaper")
|
||||
)
|
||||
return (Image) bmpTemp.Clone();
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
|
||||
|
@ -399,7 +399,7 @@ namespace CC_Functions.W32.Forms
|
||||
negativeSignKey = (Keys) VkKeyScan(negativeSignStr[0]);
|
||||
|
||||
if ((char.IsDigit((char) e.KeyCode) ||
|
||||
(e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) ||
|
||||
e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9 ||
|
||||
negativeSignKey == e.KeyCode ||
|
||||
Keys.Subtract == e.KeyCode) &&
|
||||
!e.Shift && !e.Alt && !e.Control)
|
||||
|
@ -86,9 +86,7 @@ namespace CC_Functions.W32.Forms
|
||||
dataGridView.EditingPanel.BackColor = opaqueBackColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
BackColor = dataGridViewCellStyle.BackColor;
|
||||
}
|
||||
|
||||
ForeColor = dataGridViewCellStyle.ForeColor;
|
||||
TextAlign = DataGridViewNumericUpDownCell.TranslateAlignment(dataGridViewCellStyle.Alignment);
|
||||
@ -108,10 +106,10 @@ namespace CC_Functions.W32.Forms
|
||||
if (textBox != null)
|
||||
// If the end of the selection is at the end of the string,
|
||||
// let the DataGridView treat the key message
|
||||
if ((RightToLeft == RightToLeft.No &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length)) ||
|
||||
(RightToLeft == RightToLeft.Yes &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == 0)))
|
||||
if (RightToLeft == RightToLeft.No &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length) ||
|
||||
RightToLeft == RightToLeft.Yes &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == 0))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@ -123,10 +121,10 @@ namespace CC_Functions.W32.Forms
|
||||
// If the end of the selection is at the begining of the string
|
||||
// or if the entire text is selected and we did not start editing,
|
||||
// send this character to the dataGridView, else process the key message
|
||||
if ((RightToLeft == RightToLeft.No &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == 0)) ||
|
||||
(RightToLeft == RightToLeft.Yes &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length)))
|
||||
if (RightToLeft == RightToLeft.No &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == 0) ||
|
||||
RightToLeft == RightToLeft.Yes &&
|
||||
!(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
@ -236,9 +234,7 @@ namespace CC_Functions.W32.Forms
|
||||
// the negative sign is pressed.
|
||||
bool notifyValueChange = false;
|
||||
if (char.IsDigit(e.KeyChar))
|
||||
{
|
||||
notifyValueChange = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat;
|
||||
|
@ -2,8 +2,8 @@
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using Timer = System.Timers.Timer;
|
||||
using System.Windows.Forms;
|
||||
using Timer = System.Timers.Timer;
|
||||
|
||||
namespace CC_Functions.W32.Forms
|
||||
{
|
||||
@ -15,7 +15,7 @@ namespace CC_Functions.W32.Forms
|
||||
private const double IndicatorOffset = Math.PI / 16;
|
||||
private const int MaximumIndicators = 6;
|
||||
private const int SizeFactor = 20;
|
||||
private const double StartAt = (2 * Math.PI) / 3;
|
||||
private const double StartAt = 2 * Math.PI / 3;
|
||||
private const double TimerInterval = 100.0;
|
||||
private readonly Indicator[] indicators = new Indicator[MaximumIndicators];
|
||||
private readonly Timer timer;
|
||||
@ -28,7 +28,7 @@ namespace CC_Functions.W32.Forms
|
||||
public RotatingIndicator()
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
indicators[i] = new Indicator(StartAt + (i * IndicatorOffset));
|
||||
indicators[i] = new Indicator(StartAt + i * IndicatorOffset);
|
||||
SetStyle(
|
||||
ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
|
||||
ControlStyles.SupportsTransparentBackColor, true);
|
||||
|
4
W32/Forms/SelectBox.Designer.cs
generated
4
W32/Forms/SelectBox.Designer.cs
generated
@ -1,6 +1,4 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CC_Functions.W32.Forms
|
||||
namespace CC_Functions.W32.Forms
|
||||
{
|
||||
partial class SelectBox<T>
|
||||
{
|
||||
|
@ -38,10 +38,8 @@ namespace CC_Functions.W32.Hooks
|
||||
{
|
||||
using (Process curProcess = Process.GetCurrentProcess())
|
||||
using (ProcessModule curModule = curProcess.MainModule)
|
||||
{
|
||||
return user32.SetWindowsHookEx(WH_KEYBOARD_LL, proc, kernel32.GetModuleHandle(curModule.ModuleName), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
|
@ -47,10 +47,8 @@ namespace CC_Functions.W32.Hooks
|
||||
{
|
||||
using (Process curProcess = Process.GetCurrentProcess())
|
||||
using (ProcessModule curModule = curProcess.MainModule)
|
||||
{
|
||||
return user32.SetWindowsHookEx(WH_MOUSE_LL, proc, kernel32.GetModuleHandle(curModule.ModuleName), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
|
@ -6,9 +6,10 @@ namespace CC_Functions.W32.Native
|
||||
{
|
||||
internal static class user32
|
||||
{
|
||||
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr lParam);
|
||||
public delegate bool EnumDelegate(IntPtr hWnd, int lParam);
|
||||
|
||||
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr lParam);
|
||||
|
||||
public delegate IntPtr LowLevelProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
|
@ -124,19 +124,15 @@ namespace CC_Functions.W32
|
||||
new Win32Exception());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("AdjustTokenPrivileges failed.",
|
||||
new Win32Exception());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture,
|
||||
"OpenProcessToken failed. CurrentProcess: {0}", currentProcess.ToInt32()),
|
||||
new Win32Exception());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (tokenHandle != IntPtr.Zero)
|
||||
@ -144,13 +140,11 @@ namespace CC_Functions.W32
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
string.Format(CultureInfo.InvariantCulture,
|
||||
"LookupPrivilegeValue failed. SecurityEntityValue: {0}", securityEntityValue),
|
||||
new Win32Exception());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
@ -30,10 +30,7 @@ namespace CC_Functions.W32
|
||||
|
||||
public static void Draw(Image img)
|
||||
{
|
||||
using (IDCDrawer drawerBuffered = GetDrawer())
|
||||
{
|
||||
drawerBuffered.Graphics.DrawImage(img, GetBounds());
|
||||
}
|
||||
using (IDCDrawer drawerBuffered = GetDrawer()) drawerBuffered.Graphics.DrawImage(img, GetBounds());
|
||||
}
|
||||
|
||||
public static IDCDrawer GetDrawer(bool buffer = true)
|
||||
|
@ -5,13 +5,13 @@
|
||||
<AssemblyName>CC-Functions.W32</AssemblyName>
|
||||
<LangVersion>8</LangVersion>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<TargetFrameworks>net461;netcoreapp3.1</TargetFrameworks>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<Deterministic>false</Deterministic>
|
||||
<Authors>CC24</Authors>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>W32 Additions for CC-Functions</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://github.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
|
11
W32/Wnd32.cs
11
W32/Wnd32.cs
@ -17,9 +17,7 @@ namespace CC_Functions.W32
|
||||
public sealed class Wnd32 : IEquatable<Wnd32>
|
||||
{
|
||||
#region Exposed
|
||||
|
||||
#region CreateInstance
|
||||
|
||||
private Wnd32(IntPtr handle) => HWnd = handle;
|
||||
|
||||
/// <summary>
|
||||
@ -61,7 +59,8 @@ namespace CC_Functions.W32
|
||||
/// <param name="point">The point to scan</param>
|
||||
/// <param name="visible">Whether windows need to be visible</param>
|
||||
/// <returns>The windows</returns>
|
||||
public static Wnd32[] AllFromPoint(Point point, bool visible = false) => All.Where(s => s.Position.Contains(point) && s.Shown || !visible).ToArray();
|
||||
public static Wnd32[] AllFromPoint(Point point, bool visible = false) =>
|
||||
All.Where(s => s.Position.Contains(point) && s.Shown || !visible).ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the window associated with the forms handle
|
||||
@ -100,11 +99,9 @@ namespace CC_Functions.W32
|
||||
/// The current programs console window. Do NOT use this if you are not targeting a console app or allocating a console
|
||||
/// </summary>
|
||||
public static Wnd32 ConsoleWindow => FromHandle(kernel32.GetConsoleWindow());
|
||||
|
||||
#endregion CreateInstance
|
||||
|
||||
#region InstanceActions
|
||||
|
||||
public Wnd32[] Children
|
||||
{
|
||||
get
|
||||
@ -357,13 +354,10 @@ namespace CC_Functions.W32
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion InstanceActions
|
||||
|
||||
#endregion Exposed
|
||||
|
||||
#region Internal
|
||||
|
||||
/// <summary>
|
||||
/// The windows' handle
|
||||
/// </summary>
|
||||
@ -390,7 +384,6 @@ namespace CC_Functions.W32
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Internal
|
||||
}
|
||||
}
|
5
renovate.json
Normal file
5
renovate.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user