Compare commits

...

54 Commits

Author SHA1 Message Date
JFronny
baffd311ce Make DB info public 2020-11-19 19:55:41 +01:00
JFronny
5b5e359efb Because of CI there cant be net5. sad. 2020-11-19 19:43:47 +01:00
JFronny
cae077a5cf netstandard2.1 because the world apparently isn't ready yet 2020-11-19 19:37:33 +01:00
JFronny
d80c1ac5a0 Add AspNet GenericExtensions 2020-11-19 19:35:17 +01:00
JFronny
9d87c47f1c AspNet extensions 2020-11-19 19:26:36 +01:00
JFronny
bb5ea72041 .NET Standard 2.1 & .NET 5.0 2020-11-11 16:37:40 +01:00
J. Fronny
454d902f04 Merge branch 'renovate/system.management-5.x' into 'master'
Update dependency System.Management to v5

See merge request JFronny/CC-Functions!2
2020-11-10 15:21:36 +00:00
Renovate Bot
fc68a0f6f7
Update dependency System.Management to v5 2020-11-10 12:17:13 +00:00
J. Fronny
dba8d63af5 Merge branch 'renovate/system.security.cryptography.protecteddata-5.x' into 'master'
Update dependency System.Security.Cryptography.ProtectedData to v5

See merge request JFronny/CC-Functions!3
2020-11-10 12:01:40 +00:00
Renovate Bot
65ae6b84e7
Update dependency System.Security.Cryptography.ProtectedData to v5 2020-11-10 01:18:08 +00:00
JFronny
1e451b78f9 Add initial argument parsing capabilites to CC_Functions.CommandLine 2020-09-11 11:41:08 +02:00
JFronny
7c9a5aa73d Include CC_Functions.Core in README and nugets artifact 2020-09-11 10:46:29 +02:00
JFronny
85a67cd64a [Attempt] introduce CC_Functions.Core 2020-09-11 10:38:55 +02:00
J. Fronny
0fa5fd6e82 Update .gitlab-ci.yml 2020-08-31 19:14:46 +00:00
J. Fronny
ea2572d585 Update .gitlab-ci.yml 2020-08-31 19:01:19 +00:00
J. Fronny
0743b09941 Update .gitlab-ci.yml 2020-07-31 13:36:39 +00:00
J. Fronny
45b7c9263c Add LICENSE 2020-06-27 16:23:37 +00:00
J. Fronny
94bd0fa189 Merge branch 'renovate/configure' into 'master'
Configure Renovate

See merge request JFronny/CC-Functions!1
2020-06-23 12:09:01 +00:00
Renovate Bot
3fc3cd61b5
Add renovate.json 2020-06-23 08:48:43 +00:00
J. Fronny
282a249f3f Update README.md 2020-06-18 20:02:24 +00:00
J. Fronny
a24905c884 Update README.md 2020-06-18 20:01:33 +00:00
J. Fronny
eb4d7fe2ec Delete main.yml 2020-06-18 20:00:14 +00:00
J. Fronny
fdf8afb388 Update .gitlab-ci.yml 2020-06-18 19:59:55 +00:00
J. Fronny
622d1aa130 Update .gitlab-ci.yml 2020-06-18 19:54:12 +00:00
J. Fronny
4969a420ee Update .gitlab-ci.yml 2020-06-18 19:47:23 +00:00
J. Fronny
f3cb5e136c Update .gitlab-ci.yml 2020-06-18 18:46:14 +00:00
J. Fronny
5cb6fd677a Update .gitlab-ci.yml 2020-06-18 18:40:59 +00:00
J. Fronny
f6644550a6 Update .gitlab-ci.yml 2020-06-18 18:32:38 +00:00
J. Fronny
21ab015742 Update .gitlab-ci.yml 2020-06-18 18:23:05 +00:00
J. Fronny
87b4f3fd08 Update .gitlab-ci.yml 2020-06-18 18:15:20 +00:00
J. Fronny
d7fdd3a711 Update .gitlab-ci.yml 2020-06-18 18:09:19 +00:00
J. Fronny
6b46c7950e Update .gitlab-ci.yml 2020-06-18 17:58:54 +00:00
J. Fronny
db42601eba Update .gitlab-ci.yml 2020-06-18 17:47:33 +00:00
J. Fronny
6b747bdbe8 Update .gitlab-ci.yml 2020-06-18 17:41:37 +00:00
J. Fronny
4dfb57fc2f Add .gitlab-ci.yml 2020-06-18 17:34:06 +00:00
JFronny
7699deb82c Slightly hacky fixes (most likely breaks something) 2020-06-12 19:48:31 +02:00
JFronny
30e27b9a21 No longer broken 2020-06-12 18:24:35 +02:00
JFronny
9e6b441169 ActualSize executes CalculatePosition 2020-06-12 18:16:47 +02:00
JFronny
5d380112ac Run events on all inputs 2020-06-12 16:39:02 +02:00
JFronny
d562ea5295 I am officially stupid 2020-06-12 15:49:38 +02:00
JFronny
4abc39d48b I don't know how it works, I don't want to know but it works so I won't touch it from now 2020-06-12 15:40:08 +02:00
JFronny
b56fb7db78 Remove DiffDraw.FullDraw (merged with DiffDraw.Draw) 2020-06-12 15:21:58 +02:00
JFronny
c5fc9874b1 More null proofing 2020-06-12 15:12:13 +02:00
JFronny
f0400a18bb Maybe fix stack overflow 2020-06-12 14:58:13 +02:00
JFronny
f9e7fb1f40 Fix NullReferenceException in equality operations in Pixel.cs 2020-06-12 14:48:28 +02:00
JFronny
46605e282e Make "Color" property on TUI screen accessible 2020-06-12 14:38:07 +02:00
JFronny
3f35a47e90 Dont draw on title change (prevents NullReferenceException in edge case) 2020-06-12 14:25:24 +02:00
JFronny
94d3ff2873 Prevent DivideByZero if MaxValue and MinValue are equal 2020-06-12 13:02:05 +02:00
JFronny
70fa52a59a Allow MaxValue and MinValue of TUI.Slider to be equal 2020-06-12 12:25:12 +02:00
JFronny
a70f4f4393 Call CalculatePosition if CenteredScreen.Title gets changed 2020-06-12 12:20:04 +02:00
JFronny
fb44579b33 ValueChanged event for TUI Slider 2020-06-12 11:29:07 +02:00
JFronny
79531147b2 Two minor tweaks 2020-06-12 11:24:03 +02:00
JFronny
5f3fb98999 Why where imports broken? 2020-05-25 19:32:53 +02:00
JFronny
f6950a0d4c Centered Screen (like Dialog) and fixes 2020-05-23 17:22:45 +02:00
51 changed files with 1880 additions and 814 deletions

View File

@ -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
View 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
View 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>

View 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();
}
}
}
}

View 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
View 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
View 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);
}
}
}

View File

@ -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

View File

@ -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
View 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});
}
}
}

View File

@ -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>

View File

@ -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
/// Provides differential drawing of a char[,] Do not use in combination with System.Console
/// </summary>
public static class DiffDraw
{
private static Pixel[,] _last = new Pixel[0, 0];
private static Pixel[,] Screen { get; set; } = new Pixel[0, 0];
private static Pixel[,] _last = new Pixel[0,0];
/// <summary>
/// The regions width
/// The regions width
/// </summary>
public static int Width => Screen.GetLength(1);
/// <summary>
/// The regions height
/// The regions height
/// </summary>
public static int Height => Screen.GetLength(0);
/// <summary>
/// Draws to the console
/// 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,113 +42,92 @@ 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)
{
Console.ForegroundColor = tmp1.ForeColor;
Console.BackgroundColor = tmp1.BackColor;
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;
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;
_last = Screen;
}
/// <summary>
/// Gets the char at a location
/// 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
/// Gets the char at a location
/// </summary>
/// <param name="x">The locations X coordinate</param>
/// <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
/// 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
/// Gets the foreground color at a location
/// </summary>
/// <param name="x">The locations X coordinate</param>
/// <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
/// 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
/// Gets the background color at a location
/// </summary>
/// <param name="x">The locations X coordinate</param>
/// <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
/// 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
/// Sets a pixel at a location
/// </summary>
/// <param name="x">The locations X coordinate</param>
/// <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
/// Clears the screen
/// </summary>
public static void Clear() => Clear(Width, Height);
/// <summary>
/// Resizes and clears the screen
/// Resizes and clears the screen
/// </summary>
/// <param name="width">The new width</param>
/// <param name="height">The new height</param>
@ -151,8 +136,9 @@ namespace CC_Functions.Commandline.TUI
Screen = new Pixel[height, width];
_last = _last.Resize(height, width);
}
/// <summary>
/// Replaces the screen state
/// Replaces the screen state
/// </summary>
/// <param name="content">The new state</param>
public static void Clear(Pixel[,] content)

View File

@ -1,41 +1,67 @@
using System.Collections.Generic;
using System.Drawing;
using CC_Functions.Misc;
using System.Linq;
using CC_Functions.Core;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// A basic button type
/// A basic button type
/// </summary>
public class Button : Control
{
/// <summary>
/// The text inside this button
/// The text inside this button
/// </summary>
public string Content;
/// <summary>
/// Creates a new button
/// Creates a new button
/// </summary>
/// <param name="content">The text inside this button</param>
public Button(string content)
{
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);
}
}
}

View 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;
}
}
}
}

View File

@ -1,24 +1,33 @@
using System;
using System.Drawing;
using CC_Functions.Misc;
using CC_Functions.Core;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Provides a control for users to select a boolean
/// Provides a control for users to select a boolean
/// </summary>
public class CheckBox : Control
{
/// <summary>
/// The text inside this checkbox
/// 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>
/// Whether the box is checked
/// </summary>
public bool Checked;
/// <summary>
/// The text inside this checkbox
/// </summary>
public string Content;
/// <summary>
/// Whether the box is checked
/// </summary>
public bool Checked = false;
/// <summary>
/// Creates a new checkbox
/// Creates a new checkbox
/// </summary>
/// <param name="content">The text inside this CheckBox</param>
public CheckBox(string content)
@ -43,6 +52,9 @@ namespace CC_Functions.Commandline.TUI
};
}
/// <inheritdoc />
public override bool Selectable { get; } = true;
/// <inheritdoc />
public override Pixel[,] Render()
{
@ -63,17 +75,8 @@ 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
/// Called when the state of this checkbox is changed
/// </summary>
public event OnClick CheckedChanged;
}

View File

@ -4,29 +4,45 @@ using System.Drawing;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Abstract class inherited by all controls
/// Abstract class inherited by all controls
/// </summary>
public abstract class Control
{
/// <summary>
/// Called when the controls Size property is changed
/// 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>
/// The size of the control
/// Whether the control should be rendered
/// </summary>
public bool Visible = true;
/// <summary>
/// The size of the control
/// </summary>
public Size Size
{
@ -40,61 +56,64 @@ namespace CC_Functions.Commandline.TUI
}
get => _size;
}
/// <summary>
/// The position of this control
/// 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
/// The foreground color for this control
/// </summary>
public ConsoleColor ForeColor { get; set; } = Console.ForegroundColor;
/// <summary>
/// The background color for this control
/// The background color for this control
/// </summary>
public ConsoleColor BackColor { get; set; } = Console.BackgroundColor;
/// <summary>
/// Whether the control can be selected
/// Whether the control can be selected
/// </summary>
public abstract bool Selectable { get; }
/// <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 [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
/// Whether the object is selected. Used internally and for drawing
/// </summary>
public bool Selected { get; internal set; } = false;
/// <summary>
/// Invokes click events
/// 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>
public event OnInput Input;
/// <summary>
/// Invokes click events
/// </summary>
/// <param name="screen">The calling screen</param>
internal void InvokeClick(Screen screen)
{
Click?.Invoke(screen, new EventArgs());
}
/// <summary>
/// Invokes input events
/// Invokes input events
/// </summary>
/// <param name="screen">The calling screen</param>
/// <param name="info">The input data</param>
@ -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;
}
}

View File

@ -3,19 +3,19 @@ using System;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Arguments containing input data
/// Arguments containing input data
/// </summary>
public class InputEventArgs : EventArgs
{
private readonly ConsoleKeyInfo _info;
/// <summary>
/// The inputs data
/// </summary>
public ConsoleKeyInfo Info => _info;
/// <summary>
/// Generates new arguments
/// 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; }
}
}

View File

@ -1,22 +1,47 @@
using System.Drawing;
using CC_Functions.Misc;
using CC_Functions.Core;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// A basic text control
/// A basic text control
/// </summary>
public class Label : Control
{
private string _content;
/// <summary>
/// The text inside this label
/// </summary>
public string Content;
/// <summary>
/// Creates a new label
/// 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;
}
}

View File

@ -1,41 +1,51 @@
using System.Collections.Generic;
using System.Linq;
using CC_Functions.Misc;
using CC_Functions.Core;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// A panel containing other components. MUST be inherited for all other controls that contain others
/// A panel containing other components. MUST be inherited for all other controls that contain others
/// </summary>
public class Panel : Control
{
/// <summary>
/// The controls inside this panel
/// 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
/// Renders the control and all contained controls
/// </summary>
/// <returns>The rendered pixels</returns>
public override Pixel[,] Render()
{
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
/// Recursively enumerates all controls
/// </summary>
/// <returns>A list of all controls</returns>
public Control[] EnumerateRecursive()
@ -50,4 +60,4 @@ namespace CC_Functions.Commandline.TUI
return output.ToArray();
}
}
}
}

View File

@ -4,10 +4,108 @@ using System.Collections.Generic;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Represents a pixel
/// Represents a pixel
/// </summary>
public class 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)
{
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(' ')
{
}
/// <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>
/// <param name="obj">The other object to compare</param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Pixel) obj);
}
/// <summary>
/// Generates an integer for comparing this object
/// </summary>
/// <returns>The generated hash</returns>
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) => !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 == 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)
@ -21,89 +119,5 @@ namespace CC_Functions.Commandline.TUI
public int GetHashCode(Pixel obj) => obj.GetHashCode();
}
/// <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>
/// <param name="obj">The other object to compare</param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((Pixel) obj);
}
/// <summary>
/// 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(' ')
{
}
/// <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);
/// <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);
/// <summary>
/// Returns the content of this pixel
/// </summary>
/// <returns>The content of this pixel</returns>
public override string ToString() => Content.ToString();
}
}

View File

@ -5,22 +5,72 @@ using System.Linq;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Provides a front-end renderer for panels, draws using DiffDraw
/// Provides a front-end renderer for panels, draws using DiffDraw
/// </summary>
public class Screen : Panel
{
/// <summary>
/// Whether to output in color. Recommended for most terminals, might cause slowdowns in others
/// Called if Escape is pressed, use this for flow control
/// </summary>
public readonly bool Color;
/// <param name="screen">This instance of the screen class</param>
/// <param name="e">Args</param>
public delegate void OnClose(Screen screen, EventArgs e);
/// <summary>
/// The current index of the tab-selected control in an array of selectable controls
/// Called when the selected control is changed
/// </summary>
public int TabPoint = 0;
private int _wndWidth = Console.WindowWidth;
/// <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 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
{
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
/// Creates a screen object. Multiple can be instantiated but drawing one overrides others. Use panels for that
/// </summary>
/// <param name="width">The screens with</param>
/// <param name="height">The screens height</param>
@ -28,12 +78,13 @@ namespace CC_Functions.Commandline.TUI
public Screen(int width, int height, bool color = true)
{
Color = color;
Border = false;
Resize(width, height);
Tab();
}
/// <summary>
/// Resizes the screen. Make sure that this does not exceed the console size
/// Resizes the screen. Make sure that this does not exceed the console size
/// </summary>
/// <param name="width"></param>
/// <param name="height"></param>
@ -42,13 +93,14 @@ namespace CC_Functions.Commandline.TUI
Size = new Size(width, height);
DiffDraw.Clear(width, height);
}
/// <summary>
/// Renders the screen, draws it to the console and outputs the new state
/// Renders the screen, draws it to the console and outputs the new state
/// </summary>
/// <returns>The new state of the screen</returns>
public new Pixel[,] Render()
{
FixSelection();
Pixel[,] tmp = base.Render();
DiffDraw.Clear(tmp);
DiffDraw.Draw(Color);
@ -56,9 +108,12 @@ namespace CC_Functions.Commandline.TUI
}
/// <summary>
/// Reads input from Console and calls according functions
/// 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,9 +151,12 @@ 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
/// Increases the TabPoint or reverts back to 0 if at the end of selectables
/// </summary>
/// <param name="positive">Set to false to decrease instead</param>
public void Tab(bool positive = true)
@ -111,8 +165,9 @@ 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
/// Increases the TabPoint or reverts back to 0 if at the end of selectables
/// </summary>
/// <param name="selectable">The array of selectable controls to select from. You should most likely not use this</param>
/// <param name="positive">Set to false to decrease instead</param>
@ -130,30 +185,37 @@ namespace CC_Functions.Commandline.TUI
TabPoint--;
if (TabPoint < 0) TabPoint = selectable.Length - 1;
}
foreach (Control control in selectable) control.Selected = false;
selectable[TabPoint].Selected = true;
Render();
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
/// 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
/// 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;
}
}

View File

@ -1,15 +1,24 @@
using System;
using CC_Functions.Misc;
using CC_Functions.Core;
namespace CC_Functions.Commandline.TUI
{
/// <summary>
/// Provides a control to select a number from a range of numbers
/// Provides a control to select a number from a range of numbers
/// </summary>
public class Slider : Control
{
private int _maxValue = 10;
private int _minValue;
private int _value = 5;
/// <summary>
/// Generates a new slider
/// The size of steps in this slider
/// </summary>
public int StepSize = 1;
/// <summary>
/// Generates a new slider
/// </summary>
public Slider()
{
@ -22,18 +31,21 @@ 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
/// The maximum value for this slider
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown if too low/high</exception>
public int MaxValue
@ -41,14 +53,16 @@ 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
/// The minimal value for this slider
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown if too low/high</exception>
public int MinValue
@ -56,14 +70,16 @@ 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
/// The current value of this slider
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown if too low/high</exception>
public int Value
@ -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;
}
}

View File

@ -2,43 +2,47 @@ 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
{
/// <summary>
/// A basic non-scrolling text-editor control
/// A basic non-scrolling text-editor control
/// </summary>
public class TextBox : Control
{
/// <summary>
/// The text inside this textbox
/// 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
/// The "Cursors" position in this text box
/// </summary>
public Point Cursor = new Point(0, 0);
/// <summary>
/// Creates a new text box
/// Creates a new text box
/// </summary>
/// <param name="content">The text inside this text box</param>
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
/// Function to process input
/// </summary>
/// <param name="key">The pressed key</param>
/// <param name="info">Input metadata</param>
@ -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] = ']';
}
for (int i = 0; i < Size.Width; i++) inp[i, Size.Height - 1] = '.';
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;
}
}

View File

@ -9,12 +9,13 @@ using System.Text;
namespace CC_Functions.Commandline
{
/// <summary>
/// Provides functions for parsing enumerables to powershell-like tables
/// Provides functions for parsing enumerables to powershell-like tables
/// </summary>
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,8 +24,9 @@ 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
/// Parses the array 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>
@ -53,8 +55,9 @@ namespace CC_Functions.Commandline
return ToStringTable(arrValues);
}
/// <summary>
/// Parses the array to a table
/// Parses the array to a table
/// </summary>
/// <param name="arrValues">The cells of the table</param>
/// <returns>The generated table</returns>
@ -104,8 +107,9 @@ namespace CC_Functions.Commandline
return maxColumnsWidth;
}
/// <summary>
/// Parses the enumerable to a table, transformed to strings with the specified selector
/// Parses the enumerable to a table, transformed to strings with the specified selector
/// </summary>
/// <param name="values">The values to display</param>
/// <param name="valueSelectors">Functions to get data for the cells</param>

View File

@ -2,15 +2,15 @@
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
/// Contains extension functions to work with 1D and 2D arrays
/// </summary>
public static class ArrayFormatter
{
/// <summary>
/// Copies and resizes the array
/// Copies and resizes the array
/// </summary>
/// <param name="original">The original array. This is not modified</param>
/// <param name="elements">The new amount of elements</param>
@ -23,8 +23,9 @@ namespace CC_Functions.Misc
Array.Resize(ref output, elements);
return output;
}
/// <summary>
/// Copies and resizes the array
/// Copies and resizes the array
/// </summary>
/// <param name="original">The original array. This is not modified</param>
/// <param name="rows">The new amount of elements in dimension 0</param>
@ -43,8 +44,9 @@ namespace CC_Functions.Misc
newArray[i, j] = original[i, j];
return newArray;
}
/// <summary>
/// Converts a string to a 2d char array using newlines
/// Converts a string to a 2d char array using newlines
/// </summary>
/// <param name="source">The source string</param>
/// <param name="defaultEl">The element to place in empty fields of the new array</param>
@ -64,17 +66,20 @@ namespace CC_Functions.Misc
}
return output;
}
/// <summary>
/// Clears and fills the array with the specified value
/// 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
/// 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>
@ -84,10 +89,12 @@ 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
/// Copies the content of a 2D array to another with offset
/// </summary>
/// <param name="arr">The array to copy from</param>
/// <param name="target">The array to copy to</param>
@ -101,12 +108,14 @@ namespace CC_Functions.Misc
int mh = target.GetLength(0);
int ow = offset.X;
int oh = offset.Y;
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];
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)
/// Copies and rotates the 2d array (row->column, column->row)
/// </summary>
/// <param name="arr">The array to copy from</param>
/// <typeparam name="T">The type of elements in the array</typeparam>
@ -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
View 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
View 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;
}
}
}

View File

@ -1,15 +1,15 @@
using System;
using System.IO;
namespace CC_Functions.Misc
namespace CC_Functions.Core
{
/// <summary>
/// IO functions
/// IO functions
/// </summary>
public static class IO
{
/// <summary>
/// Recursively gets the size of an directory
/// Recursively gets the size of an directory
/// </summary>
/// <param name="path">The path of the directory</param>
/// <returns>The size of the directory</returns>
@ -21,8 +21,9 @@ namespace CC_Functions.Misc
size += new FileInfo(t).Length;
return size;
}
/// <summary>
/// Check whether the paths are equivalent (ignores case)
/// Check whether the paths are equivalent (ignores case)
/// </summary>
/// <param name="path1">The first path to check</param>
/// <param name="path2">The second path to check</param>

156
Core/SpecialChars.cs Normal file
View 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
View 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.

View File

@ -5,12 +5,12 @@ using System.Security.Cryptography;
namespace CC_Functions.Misc
{
/// <summary>
/// Contains cryptographic functions
/// Contains cryptographic functions
/// </summary>
public static class Crypto
{
/// <summary>
/// Encrypts an array of bytes using SHA512. Use with <see cref="Decrypt">Decrypt</see>
/// Encrypts an array of bytes using SHA512. Use with <see cref="Decrypt">Decrypt</see>
/// </summary>
/// <param name="data">The array of bytes to encrypt</param>
/// <param name="key">The key for encryption, later required to decrypt</param>
@ -49,8 +49,9 @@ namespace CC_Functions.Misc
return combined;
}
/// <summary>
/// Decrypts an SHA512-encrypted byte array. Use with <see cref="Encrypt">Encrypt</see>
/// Decrypts an SHA512-encrypted byte array. Use with <see cref="Encrypt">Encrypt</see>
/// </summary>
/// <param name="encrypted">The array of bytes to decrypt</param>
/// <param name="key">The key the data was encrypted with</param>

View File

@ -1,236 +1,27 @@
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
{
/// <summary>
/// Extension methods for various types
/// 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>
/// 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
/// Extension method for <see cref="Crypto">Crypto's</see> Encrypt
/// </summary>
/// <param name="self">The data to encrypt</param>
/// <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
/// Extension method for <see cref="Crypto">Crypto's</see> Decrypt
/// </summary>
/// <param name="self">The data to decrypt</param>
/// <param name="key">The key to decrypt with</param>

View File

@ -8,17 +8,18 @@ using System.Text;
namespace CC_Functions.Misc
{
/// <summary>
/// Functions for hardware identidiers
/// Functions for hardware identidiers
/// </summary>
public static class Hid
{
/// <summary>
/// Whether to force Win32-based operation
/// 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,8 +34,9 @@ Win32_BaseBoard:Manufacturer
Win32_BaseBoard:Name
Win32_BaseBoard:SerialNumber
Win32_NetworkAdapterConfiguration:MACAddress";
/// <summary>
/// The HID for this machine
/// The HID for this machine
/// </summary>
public static byte[] Value
{
@ -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))
{
HIDClasses.Split(new[] {"\r\n"}, StringSplitOptions.None).Select(s =>
if (ForceWindows ||
new[]
{
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,15 +104,17 @@ Win32_NetworkAdapterConfiguration:MACAddress";
return _fingerPrint;
}
}
/// <summary>
/// Encrypts data using <see cref="Crypto">Crypto's</see> Encrypt and the HID
/// Encrypts data using <see cref="Crypto">Crypto's</see> Encrypt and the HID
/// </summary>
/// <param name="unencrypted">The data to encrypt</param>
/// <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
/// Decrypts data using <see cref="Crypto">Crypto's</see> Decrypt and the HID
/// </summary>
/// <param name="encrypted">The data to decrypt</param>
/// <returns>The decrypted data</returns>

View File

@ -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>
</Project>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
</Project>

View File

@ -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 = ' ';
}
}

View File

@ -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/)
# CC-Functions
[![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/)

View File

@ -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));
@ -101,13 +102,13 @@ namespace CC_Functions.W32.Test
FormBorderStyle = FormBorderStyle.None,
WindowState = FormWindowState.Maximized
};
Label lab = new Label { AutoSize = true };
Label lab = new Label {AutoSize = true};
frm.Controls.Add(lab);
Panel pan = new Panel { BackColor = Color.Red };
Panel pan = new Panel {BackColor = Color.Red};
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)
{

View File

@ -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; }
}
}

View File

@ -16,10 +16,9 @@ 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
{

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -1,6 +1,4 @@
using System.Windows.Forms;
namespace CC_Functions.W32.Forms
namespace CC_Functions.W32.Forms
{
partial class SelectBox<T>
{

View File

@ -38,9 +38,7 @@ 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)

View File

@ -47,9 +47,7 @@ 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)

View File

@ -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")]
@ -130,7 +131,7 @@ namespace CC_Functions.W32.Native
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);

View File

@ -124,18 +124,14 @@ 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
{
@ -144,12 +140,10 @@ namespace CC_Functions.W32
}
}
else
{
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture,
"LookupPrivilegeValue failed. SecurityEntityValue: {0}", securityEntityValue),
new Win32Exception());
}
}
catch (Exception e)
{

View File

@ -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)

View File

@ -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>

View File

@ -16,10 +16,8 @@ namespace CC_Functions.W32
/// </summary>
public sealed class Wnd32 : IEquatable<Wnd32>
{
#region Exposed
#region CreateInstance
#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
#endregion CreateInstance
#region InstanceActions
#region InstanceActions
public Wnd32[] Children
{
get
@ -357,13 +354,10 @@ namespace CC_Functions.W32
return true;
}
}
#endregion InstanceActions
#endregion Exposed
#endregion InstanceActions
#endregion Exposed
#region Internal
#region Internal
/// <summary>
/// The windows' handle
/// </summary>
@ -378,7 +372,7 @@ namespace CC_Functions.W32
_windowHandles.Add(hWnd);
return true;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
@ -390,7 +384,6 @@ namespace CC_Functions.W32
return true;
}
#endregion Internal
#endregion Internal
}
}

5
renovate.json Normal file
View File

@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}