diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1ff0c42..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
index 4547d9e..9488398 100644
--- a/.gitignore
+++ b/.gitignore
@@ -362,6 +362,5 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
-# Test files
-Test/
-Readme images/
\ No newline at end of file
+# secret files
+secret/
diff --git a/Forms/AskPathForm.Designer.cs b/Forms/AskPathForm.Designer.cs
new file mode 100644
index 0000000..e0ed501
--- /dev/null
+++ b/Forms/AskPathForm.Designer.cs
@@ -0,0 +1,107 @@
+namespace SteamVR_OculusDash_Switcher.Forms
+{
+ partial class AskPathForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.lbText = new System.Windows.Forms.Label();
+ this.btnApply = new System.Windows.Forms.Button();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.lbPath = new System.Windows.Forms.Label();
+ this.btnBrowse = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // lbText
+ //
+ this.lbText.AutoSize = true;
+ this.lbText.Location = new System.Drawing.Point(12, 9);
+ this.lbText.Name = "lbText";
+ this.lbText.Size = new System.Drawing.Size(59, 25);
+ this.lbText.TabIndex = 0;
+ this.lbText.Text = "label1";
+ //
+ // btnApply
+ //
+ this.btnApply.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.btnApply.Location = new System.Drawing.Point(0, 193);
+ this.btnApply.Name = "btnApply";
+ this.btnApply.Size = new System.Drawing.Size(844, 39);
+ this.btnApply.TabIndex = 0;
+ this.btnApply.Text = "Apply";
+ this.btnApply.UseVisualStyleBackColor = true;
+ //
+ // textBox1
+ //
+ this.textBox1.Location = new System.Drawing.Point(68, 51);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(356, 31);
+ this.textBox1.TabIndex = 0;
+ //
+ // lbPath
+ //
+ this.lbPath.AutoSize = true;
+ this.lbPath.Location = new System.Drawing.Point(12, 54);
+ this.lbPath.Name = "lbPath";
+ this.lbPath.Size = new System.Drawing.Size(50, 25);
+ this.lbPath.TabIndex = 1;
+ this.lbPath.Text = "Path:";
+ //
+ // btnBrowse
+ //
+ this.btnBrowse.Location = new System.Drawing.Point(430, 49);
+ this.btnBrowse.Name = "btnBrowse";
+ this.btnBrowse.Size = new System.Drawing.Size(112, 34);
+ this.btnBrowse.TabIndex = 2;
+ this.btnBrowse.Text = "Browse";
+ this.btnBrowse.UseVisualStyleBackColor = true;
+ //
+ // AskPathForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(844, 232);
+ this.Controls.Add(this.btnBrowse);
+ this.Controls.Add(this.lbText);
+ this.Controls.Add(this.btnApply);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.lbPath);
+ this.Name = "AskPathForm";
+ this.Text = "AskPath";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label lbText;
+ private System.Windows.Forms.Button btnApply;
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Label lbPath;
+ private System.Windows.Forms.Button btnBrowse;
+ }
+}
\ No newline at end of file
diff --git a/Forms/AskPathForm.cs b/Forms/AskPathForm.cs
new file mode 100644
index 0000000..5f5d2d9
--- /dev/null
+++ b/Forms/AskPathForm.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Windows.Forms;
+
+namespace SteamVR_OculusDash_Switcher.Forms
+{
+ public partial class AskPathForm : Form
+ {
+ ///
+ /// Not ready. Not used
+ ///
+ public AskPathForm()
+ {
+ InitializeComponent();
+ }
+
+ public DialogResult ShowDialog(string text)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/Forms/AskPathForm.resx b/Forms/AskPathForm.resx
new file mode 100644
index 0000000..f298a7b
--- /dev/null
+++ b/Forms/AskPathForm.resx
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Forms/ControlsTipsForm.cs b/Forms/ControlsTipsForm.cs
index e575b7b..62a9587 100644
--- a/Forms/ControlsTipsForm.cs
+++ b/Forms/ControlsTipsForm.cs
@@ -1,13 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Drawing;
using System.Windows.Forms;
-using SteamVR_OculusDash_Switcher.Properties;
using SteamVR_OculusDash_Switcher.Properties.Localization;
using Titanium;
using static Titanium.Forms;
diff --git a/Forms/SettingsForm.Designer.cs b/Forms/SettingsForm.Designer.cs
index bc69fe2..232d96b 100644
--- a/Forms/SettingsForm.Designer.cs
+++ b/Forms/SettingsForm.Designer.cs
@@ -164,7 +164,7 @@ private void InitializeComponent()
this.gbInterface.Controls.Add(this.comboLanguage);
this.gbInterface.Location = new System.Drawing.Point(318, 12);
this.gbInterface.Name = "gbInterface";
- this.gbInterface.Size = new System.Drawing.Size(267, 315);
+ this.gbInterface.Size = new System.Drawing.Size(295, 315);
this.gbInterface.TabIndex = 999;
this.gbInterface.TabStop = false;
this.gbInterface.Text = "Interface";
@@ -181,14 +181,16 @@ private void InitializeComponent()
// lbTrayIconColorValue
//
this.lbTrayIconColorValue.AutoSize = true;
+ this.lbTrayIconColorValue.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.lbTrayIconColorValue.Cursor = System.Windows.Forms.Cursors.Hand;
+ this.lbTrayIconColorValue.Font = new System.Drawing.Font("DejaVu Sans", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
this.lbTrayIconColorValue.ForeColor = System.Drawing.SystemColors.MenuHighlight;
this.lbTrayIconColorValue.Location = new System.Drawing.Point(135, 263);
this.lbTrayIconColorValue.Margin = new System.Windows.Forms.Padding(0);
this.lbTrayIconColorValue.Name = "lbTrayIconColorValue";
- this.lbTrayIconColorValue.Size = new System.Drawing.Size(105, 25);
+ this.lbTrayIconColorValue.Size = new System.Drawing.Size(157, 23);
this.lbTrayIconColorValue.TabIndex = 1004;
- this.lbTrayIconColorValue.Text = "White/Black";
+ this.lbTrayIconColorValue.Text = "◄ White/Black ►";
this.lbTrayIconColorValue.Click += new System.EventHandler(this.lbTrayIconColorValue_Click);
//
// lbTrayIconColor
diff --git a/Forms/SettingsForm.cs b/Forms/SettingsForm.cs
index 3d61176..4fc4876 100644
--- a/Forms/SettingsForm.cs
+++ b/Forms/SettingsForm.cs
@@ -1,11 +1,8 @@
using System;
-using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
-using System.Linq;
using System.Media;
-using System.Resources;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -13,7 +10,6 @@
using SteamVR_OculusDash_Switcher.Properties;
using SteamVR_OculusDash_Switcher.Properties.Localization;
using Titanium;
-using TitaniumComparator.LogicClasses;
using static SteamVR_OculusDash_Switcher.Program;
using static Titanium.Forms;
@@ -101,6 +97,8 @@ public void InitializeControls()
lbSaved.Text = LocalizationStrings.SettingsForm_btnApply_label__Saved;
lbSaved.Left = btnApply.Left - MeasureText(lbSaved).Width; //- lbSaved.Margin.Right;
lbSaved.ForeColor = this.BackColor;
+ gbFunctions.Text = LocalizationStrings.SettingsForm__Main_functions;
+ gbInterface.Text = LocalizationStrings.SettingsForm__Interface;
//btnApply.Enabled = false;
@@ -128,17 +126,25 @@ public void InitializeControls()
#region Обработчики событий
//\---------------
- //% SETTINGS APPLY
+ //! SETTINGS APPLY
//\---------------
private void btnApply_Click(object sender, EventArgs e)
{
try
{
- bool restartControlBecouseStupidWinformsCantDoSuchBasicThingAsClearCombobox = false; //TODO: Someone plaese say me how to clear combobox and it's work without -1 index exception that if it's possible
+ bool restartControlBecouseStupidWinformsCantDoSuchBasicThingAsClearCombobox = false; //TODO: Someone plaese say me how to clear combobox and it's work without -1 index exception if it's possible
+
+ //! LANGUAGE CHANGE
if (!Equals(Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName, ((Language)comboLanguage.SelectedItem).Culture.TwoLetterISOLanguageName))
{
Thread.CurrentThread.CurrentUICulture = ((Language)comboLanguage.SelectedItem).Culture;
restartControlBecouseStupidWinformsCantDoSuchBasicThingAsClearCombobox = true;
+
+ ErrorTaskDialog.InitializeDictionary(
+ LocalizationStrings.ErrorTaskDialog__OpenMicrosoftDocs,
+ LocalizationStrings.ErrorTaskDialog__Copy_to_Clipboard,
+ LocalizationStrings.ErrorTaskDialog__Open_Inner_Exception,
+ LocalizationStrings.Button__Close);
}
if (comboSteamVRDisableMethod.SelectedItem!= null && Settings.Default.SteamVRDisablingMethod != (SteamVRMethod)comboSteamVRDisableMethod.SelectedItem)
@@ -209,9 +215,9 @@ private async void btnCheckOculusKillerUpdates_Click(object sender, EventArgs e)
var status = await OculusDash.CheckKiller(true);
MessageBox.Show(status switch
{
- OculusDash.Status.Downloaded => LocalizationStrings.OculusKiller_StatusDiscription_Downloaded,
- OculusDash.Status.Updated => LocalizationStrings.OculusKiller_StatusDiscription_Updated,
- OculusDash.Status.NoAction => LocalizationStrings.OculusKiller_StatusDiscription_NoAction
+ GitHub.Status.Downloaded => LocalizationStrings.OculusKiller_StatusDiscription_Downloaded,
+ GitHub.Status.Updated => LocalizationStrings.OculusKiller_StatusDiscription_Updated,
+ GitHub.Status.NoAction => LocalizationStrings.OculusKiller_StatusDiscription_NoAction
}, "Updated", MessageBoxButtons.OK, MessageBoxIcon.Information);
btnCheckOculusKillerUpdates.Text = LocalizationStrings.SettingsForm_btnCheckOculusKillerUpdates;
btnCheckOculusKillerUpdates.Enabled = true;
@@ -278,7 +284,7 @@ private void lbIconsRealism_Resize(object sender, EventArgs e)
private void SetTrayColorValue()
{
- lbTrayIconColorValue.Text = Settings.Default.BlackMode ? LocalizationStrings.SettingsForm_lbTrayIconColorValue_Black + "►" : "◄" + LocalizationStrings.SettingsForm_lbTrayIconColorValue_White;
+ lbTrayIconColorValue.Text = Settings.Default.BlackMode ? LocalizationStrings.SettingsForm_lbTrayIconColorValue_Black + " ►" : "◄ " + LocalizationStrings.SettingsForm_lbTrayIconColorValue_White;
}
private void Change_IconRealism_DiscriptionAndImage()
diff --git a/LICENSE b/LICENSE
index ad3dccf..ba2400a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,10 +2,6 @@ Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public L
CC BY-NC-SA
-Please, note that this licence is not applying to all files under `Titanium` namespace. They may use other licence specified in file (if other licence is not specified, they inherit project's licence (this)). In this project these files are:
-Logic/Titanium.cs
-Logic/TitaniumForms.cs
-
Short:
You are free to:
Share — copy and redistribute the material in any medium or format
diff --git a/Logic/AnimationManager.cs b/Logic/AnimationManager.cs
index 9377cc2..2ab3001 100644
--- a/Logic/AnimationManager.cs
+++ b/Logic/AnimationManager.cs
@@ -3,10 +3,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
-using System.Linq;
using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
namespace SteamVR_OculusDash_Switcher.Logic
{
diff --git a/Logic/ErrorTaskDialog.cs b/Logic/ErrorTaskDialog.cs
deleted file mode 100644
index db66fe6..0000000
--- a/Logic/ErrorTaskDialog.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using SteamVR_OculusDash_Switcher.Properties.Localization;
-using TaskDialogButton = Ookii.Dialogs.WinForms.TaskDialogButton;
-
-namespace TitaniumComparator.LogicClasses
-{
- public static class ErrorTaskDialog
- {
- public static void ShowMessageBox(this Exception? Error)
- {
- if(Error == null) return;
-
- Ookii.Dialogs.WinForms.TaskDialog taskDialog = new();
- taskDialog.Content = Error.Message;
- //if(Error.Data.Count!=0) taskDialog.CollapsedControlText = Error.Data.ToDictionary().ToStringT();
- if(Error.HelpLink!=null) taskDialog.Footer = $"{LocalizationStrings.ErrorTaskDialog__OpenMicrosoftDocs}";
- TaskDialogButton closeBtn = new(LocalizationStrings.Button__Close),
- copyBtn = new(LocalizationStrings.ErrorTaskDialog__Copy_to_Clipboard),
- innerExceptionBtn = new(LocalizationStrings.ErrorTaskDialog__Open_Inner_Exception);
- innerExceptionBtn.Enabled = Error.InnerException != null;
- taskDialog.Buttons.Add(closeBtn);
- taskDialog.Buttons.Add(copyBtn);
- taskDialog.Buttons.Add(innerExceptionBtn);
-
- var button = taskDialog.ShowDialog();
- if(button == closeBtn) taskDialog.Dispose();
- if(button == copyBtn) {Thread thread = new(() => Clipboard.SetText(Error.Message));
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- Error.ShowMessageBox();
- }
- if(button == innerExceptionBtn)
- Error.InnerException.ShowMessageBox();
- }
- }
-}
diff --git a/Logic/GitHub.cs b/Logic/GitHub.cs
new file mode 100644
index 0000000..fac0403
--- /dev/null
+++ b/Logic/GitHub.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using ICSharpCode.SharpZipLib.Zip;
+using Octokit;
+using Octokit.Internal;
+using FileMode = System.IO.FileMode;
+
+namespace Titanium;
+
+public static class GitHub
+{
+ public enum Status
+ {
+ Downloaded,
+ Updated,
+ NoAction
+ }
+
+ public static string ProxyAddress = "auto";
+
+ public class UpdateResult
+ {
+ public Status Status;
+ public string? ReleaseDiscription { get; private set; }
+ public string? ReleaseName { get; private set; }
+ public Version? Version { get; private set; }
+
+ public UpdateResult(Status Status = Status.NoAction, Version? Version = null, string? ReleaseName = null, string? ReleaseDiscription = null)
+ {
+ this.Status = Status;
+ this.ReleaseDiscription = ReleaseDiscription;
+ this.ReleaseName = ReleaseName;
+ this.Version = Version;
+ }
+
+ public UpdateResult Change(Status? Status = null, Version? Version = null, string? ReleaseName = null, string? ReleaseDiscription = null)
+ {
+ if (Status!=null) this.Status = (Status)Status;
+ if (ReleaseDiscription!=null) this.ReleaseDiscription = ReleaseDiscription;
+ if (ReleaseName!=null) this.ReleaseName = ReleaseName;
+ if (Version!=null) this.Version = Version;
+ return this;
+ }
+ }
+
+
+ public enum UpdateMode
+ {
+ /// Download programm if it's not exist, but don't update it if it's exist
+ Download,
+ /// Only checks a new version, but not update it.
+ Check,
+ /// Update programm only if it's not installed or older version is installed
+ Update,
+ /// Update programm even if the newer version is installed
+ Replace
+ }
+
+ ///
+ /// Updates the exe in specified paths from GitHub releases page
+ ///
+ /// GitHub repository link from where updates will be downloaded. In any format from "https://github.com/TuTAH1/xml-js-Parser/releases/tag/1.2.0" to just "TuTAH1/xml-js-Parser" (both variants will give the same result)
+ /// Path of physical exe file that should be updated
+ /// Should archives be unpacked while placing in
+ /// regex of the filename of the release
+ /// Leave GitHub release files in ./Temp. Don't Forget to DELETE TEMP folder after performing needed operations
+ /// List of files that shouldn't extracted from downloaded archive. If null, all files will be extracted
+ /// Turns Blacklist into whitelist if true
+ /// Function that will be executed if update found. If this function will return false, update will be canceled
+ ///
+ public static async Task checkSoftwareUpdatesByLink(UpdateMode UpdateMode, string repositoryLink, string ProgramExePath, string DownloadPath = "Temp", bool ClearDownloadFolder = false, bool Unpack = true, Regex? GitHubFilenameRegex = null, bool ReverseGithubFilenameRegex = false, bool TempFolder = false, Regex[] ArchiveIgnoreFileList = null, bool ReverseArchiveFileList = false, bool KillRelatedProcesses = false, Func AskUpdate = default)
+ {
+ string[] ss = repositoryLink.RemoveFrom(TypesFuncs.Side.Start, "https://", "github.com/").Split("/");
+ if (ss.Length < 2) throw new ArgumentException("Can't get username and repName from " + repositoryLink);
+ return await checkSoftwareUpdates(UpdateMode, ss[0], ss[1], ProgramExePath, DownloadPath,ClearDownloadFolder, Unpack: Unpack, GitHubFilenameRegex: GitHubFilenameRegex,ReverseGithubFilenameRegex: ReverseGithubFilenameRegex, TempFolder: TempFolder, ArchiveIgnoreFileList: ArchiveIgnoreFileList, ReverseArchiveFileList: ReverseArchiveFileList, KillRelatedProcesses: KillRelatedProcesses, AskUpdate: AskUpdate).ConfigureAwait(false);
+ }
+
+ ///
+ /// Updates the exe in specified paths from GitHub releases page
+ ///
+ /// ///
+ ///
+ /// Repository author id (example: TuTAH1)
+ /// Repository name (example: SteamVR-OculusDash-Switcher)
+ /// Path of physical exe file that should be updated
+ ///
+ ///
+ /// Should archives be unpacked while placing in
+ /// regex of the filename of the release
+ ///
+ /// Leave GitHub release files in ./Temp. Don't Forget to DELETE TEMP folder after performing needed operations
+ /// List of files that shouldn't extracted from downloaded archive. If null, all files will be extracted
+ /// Turns Blacklist into whitelist if true
+ ///
+ /// Function that will be executed if update found. If this function will return false, update will be canceled
+ ///
+ public static async Task checkSoftwareUpdates(UpdateMode UpdateMode, string author, string repName, string ProgramExePath, string DownloadPath = "Temp", bool ClearDownloadFolder = false, bool Unpack = true, Regex GitHubFilenameRegex = null, bool ReverseGithubFilenameRegex = false, bool TempFolder = false, Regex[] ArchiveIgnoreFileList = null, bool ReverseArchiveFileList = false, bool? KillRelatedProcesses = false, Func AskUpdate = default)
+
+ {
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+ KillRelatedProcesses ??= !TempFolder;
+
+ //string registyProxyAddress = @"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings";
+ //string? proxyConfigScriptLink = Registry.GetValue(registyProxyAddress,"AutoConfigURL", null)?.ToString();
+ //bool proxyEnabled = Registry.GetValue(registyProxyAddress, "ProxyEnable",null)?.ToString() == 1.ToString() || !proxyConfigScriptLink.IsNullOrEmpty();
+
+ HttpClientHandler clientHandler = new HttpClientHandler();
+ clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
+ var webProxy = new WebProxy();
+
+ clientHandler.Proxy = ProxyAddress switch
+ {
+ "auto" => (HttpClient.DefaultProxy)
+ ,"no" => null
+ ,_=> new WebProxy(new Uri(ProxyAddress))
+ };
+
+
+ var connection = new Connection(
+ new ProductHeaderValue("Titanium-GithubSoftwareUpdater"),
+ new HttpClientAdapter(() => clientHandler));
+
+ var github = new GitHubClient(connection);
+ var release = await github.Repository.Release.GetLatest(author, repName).ConfigureAwait(false);
+ Version? relVersion = null;
+ try
+ {
+ relVersion = Version.Parse(new Regex("[^.0-9]").Replace(release.TagName, ""));
+ } catch (Exception) { }
+ UpdateResult result = new(Status.NoAction, relVersion, release.Name, release.Body);
+
+ bool fileExist = File.Exists(ProgramExePath);
+
+ if (UpdateMode!= UpdateMode.Check && !fileExist || UpdateMode == UpdateMode.Replace)
+ {
+ await DownloadLastest().ConfigureAwait(false);
+ return result.Change(Status.Downloaded);
+ }
+ else if (UpdateMode is UpdateMode.Update or UpdateMode.Check)
+ {
+ var currentVersion = FileVersionInfo.GetVersionInfo(ProgramExePath);
+ if (currentVersion is null)
+ throw new InvalidOperationException("Product version field is empty");
+
+ //:If current file's version is higher than in github, don't do anything
+ if (UpdateMode == UpdateMode.Check || relVersion <= Version.Parse(currentVersion.ProductVersion!)) return result;
+
+ if (AskUpdate == default || !AskUpdate(result))
+ return result;
+ await DownloadLastest().ConfigureAwait(false);
+ return result.Change(Status.Updated);
+ }
+ return result;
+
+ async Task DownloadLastest()
+ {
+
+ var gitHubFiles = release.Assets;
+
+ if (!gitHubFiles.Any()) throw new ArgumentNullException(nameof(gitHubFiles), "No any files found in the release");
+
+ gitHubFiles = (
+ from file in gitHubFiles
+ where (GitHubFilenameRegex?.IsMatch(file.Name) ^ ReverseGithubFilenameRegex ?? true) //: Select all files aliased with GitHubFilename regex
+ select file).ToList();
+
+ if (!gitHubFiles.Any()) throw new ArgumentNullException(nameof(gitHubFiles),GitHubFilenameRegex==null? "No files found in the release" : $"No files matching \"{GitHubFilenameRegex}\" found in the release");
+
+ foreach (var file in gitHubFiles)
+ {
+ string filepath = $"{DownloadPath}\\{file.Name}";
+
+ using var client = new HttpClient();
+ var s = await client.GetStreamAsync(file.BrowserDownloadUrl).ConfigureAwait(false);
+ if(ClearDownloadFolder)
+ try {IO.RemoveAll(DownloadPath, false); } catch (Exception) {}
+ Directory.CreateDirectory(filepath.Slice(0,"\\"));
+ var fs = new FileStream(filepath, FileMode.OpenOrCreate); //TODO: Заменить Temp на DownloadPath
+ s.CopyTo(fs); //TODO: may be done async
+ fs.Close();
+ s.Close();
+
+ Unpack = Unpack && new FileInfo(filepath).Extension == ".zip";
+ if (Unpack)
+ {
+ if ((bool)KillRelatedProcesses)
+ {
+ var archive = new ZipFile(fs.Name);
+ foreach (ZipEntry entry in archive)
+ {
+ var entryPath = (TempFolder ? "Temp\\" : "") + entry.Name;
+ var entryName = entryPath.Slice("\\", LastStart: true);
+
+ if ((bool)KillRelatedProcesses && entryName.EndsWith(".exe"))
+ TypesFuncs.KillProcesses(Path: AppContext.BaseDirectory + entryName, Name: entryName);
+ }
+
+ archive.Close();
+ }
+
+ ZipStrings.CodePage = 866;
+ new FastZip { EntryFactory = new ZipEntryFactory { IsUnicodeText = true } }.ExtractZip(filepath, (TempFolder? "Temp\\" : ""), null);
+ File.Delete(filepath);
+ }
+ else
+ {
+ File.Move(filepath, filepath.RemoveFrom(TypesFuncs.Side.Start, "Temp\\"), true);
+ }
+ }
+
+
+ //new WebClient().DownloadFile(releasesPage, "OculusDash.exe");
+ return true;
+ }
+
+
+ }
+
+ class GitHubFile
+ {
+ public string Name;
+ public string Link;
+ public Classes.FileSize? Size;
+ public DateTime? Date;
+
+ public GitHubFile(string Name, string Link, string Size, string Date)
+ {
+ this.Name = Name;
+ this.Link = Link;
+ this.Size = Classes.FileSize.Get(Size);
+ try
+ { this.Date = Convert.ToDateTime(Date); }
+ catch (Exception)
+ { this.Date = null; }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Logic/Internet.cs b/Logic/Internet.cs
index a941d96..cb20f12 100644
--- a/Logic/Internet.cs
+++ b/Logic/Internet.cs
@@ -1,17 +1,11 @@
using System;
using System.IO;
using System.Net; //для работы с интернетом
-
-using System.Collections.Generic;
-using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using System.Data.SqlClient;
using AngleSharp;
using AngleSharp.Dom;
-using AngleSharp.Html.Dom;
using AngleSharp.Io;
-using static System.Console;
namespace DataCollector
{
diff --git a/Logic/Logic.zip b/Logic/Logic.zip
new file mode 100644
index 0000000..4b127be
Binary files /dev/null and b/Logic/Logic.zip differ
diff --git a/Logic/OculusDash.cs b/Logic/OculusDash.cs
index 1a011ff..8441f0a 100644
--- a/Logic/OculusDash.cs
+++ b/Logic/OculusDash.cs
@@ -1,99 +1,78 @@
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using AngleSharp.Dom;
using DataCollector;
using Microsoft.Win32;
+using SteamVR_OculusDash_Switcher.Properties.Localization;
using Titanium;
namespace SteamVR_OculusDash_Switcher.Logic
{
public static class OculusDash
{
- private static readonly string _oculusFolderPath = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Oculus")?.GetValue("InstallLocation")?.ToString()?? (Directory.Exists( @"C:\Program Files\Oculus\")? @"C:\Program Files\Oculus\" : null);
+ private static readonly string _oculusFolderPath;
/// OculusDash.exe path
- private static readonly string _oculusDashExePath = _oculusFolderPath?.Add("\\" + @"Support\oculus-dash\dash\bin\OculusDash.exe");
+ private static readonly string _oculusDashExePath;
///Oculus killere exe's location inside of this program's folder
const string _innerOculusKillerPath = @"OculusDashKiller\OculusDash.exe";
private static bool OculusKillerChecked = false;
- public static bool IsOculusKillerExist => File.Exists(_innerOculusKillerPath);
- public static bool IsOculusExist => _oculusFolderPath != null;
- public enum Status
+ static OculusDash()
{
- Downloaded,
- Updated,
- NoAction
- }
+ _oculusFolderPath = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Oculus")?.GetValue("InstallLocation")?.ToString()?? (Directory.Exists( @"C:\Program Files\Oculus\")? @"C:\Program Files\Oculus\" : null); //: Check where Oculus is installed, if not found, set default path
- //TODO: Make it async
- //:Checks if OculusKiller exe exist and downloads the lastest release if not
- private static async Task checkOculusKiller(bool checkUpdates)
- {
- const string oculusDashDownloadLink = @"https://github.com/ItsKaitlyn03/OculusKiller/releases/latest/download/OculusDash.exe";
-
- if (!IsOculusKillerExist)
- {
- await DownloadLastestOculusKiller();
- return Status.Downloaded;
- }
- else if (checkUpdates)
+ if (_oculusFolderPath == null)
{
- var doc = await Internet.getResponseAsync(@"https://github.com/ItsKaitlyn03/OculusKiller/releases");
- var lastestVersion = doc.QuerySelector(".ml-1.wb-break-all")?.Text();
- if (lastestVersion is null)
- throw new ArgumentNullException(nameof(lastestVersion), "Can't get lastest version");
-
- var currentVersion = FileVersionInfo.GetVersionInfo(_innerOculusKillerPath);
- if (currentVersion is null)
- throw new InvalidOperationException("Product version field is empty");
-
- lastestVersion = new Regex("[^.0-9]").Replace(lastestVersion, "");
-
- /*MessageBox.Show($"Lastest version: {lastestVersion};" +
- $"\nParsed: {Version.Parse(lastestVersion)}" +
- $"\n Current version: {currentVersion.ProductVersion}" +
- $"\n Parsed: {Version.Parse(currentVersion.ProductVersion)}");*/
-
-
- //:If current file's version is lower than in github, download lastest from github
- if (Version.Parse(lastestVersion) > Version.Parse(currentVersion.ProductVersion))
+ var drives = DriveInfo.GetDrives();
+ foreach (var drive in drives)
{
- await DownloadLastestOculusKiller(); //! Not checked
- return Status.Updated;
+ string driveLetter = drive.RootDirectory.FullName;
+ string oculusFolderPath = Path.Combine(driveLetter, @"Oculus\");
+ if (!Directory.Exists(oculusFolderPath)) continue;
+
+ _oculusFolderPath = oculusFolderPath;
+ break;
}
}
- return Status.NoAction;
- async Task DownloadLastestOculusKiller()
+ if (_oculusFolderPath == null)
{
- using (var client = new HttpClient())
+ using var fbd = new FolderBrowserDialog();
+ fbd.Description = LocalizationStrings.OculusDash_OculusNotFound__Select_Oculus_folder_path;
+ DialogResult result = fbd.ShowDialog();
+
+ if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath))
{
- var s = await client.GetStreamAsync(oculusDashDownloadLink);
- Directory.CreateDirectory(_innerOculusKillerPath.Slice(0,"\\"));
- var fs = new FileStream(_innerOculusKillerPath, FileMode.OpenOrCreate);
- s.CopyTo(fs); //TODO: may be done async
+ string[] files = Directory.GetFiles(fbd.SelectedPath);
}
-
- new WebClient().DownloadFile(oculusDashDownloadLink, "OculusDash.exe");
- return true;
}
+
+ _oculusDashExePath = _oculusFolderPath?.Add("\\" + @"Support\oculus-dash\dash\bin\OculusDash.exe");
+ }
+
+ public static bool IsOculusKillerExist => File.Exists(_innerOculusKillerPath);
+ public static bool IsOculusExist => _oculusFolderPath != null;
+
+
+ //:Checks if OculusKiller exe exist and downloads the lastest release if not
+ private static async Task checkOculusKiller(bool checkUpdates)
+ {
+ const string oculusDashRepository = @"ItsKaitlyn03/OculusKiller";
+ return(await GitHub.checkSoftwareUpdatesByLink(GitHub.UpdateMode.Update, oculusDashRepository,_innerOculusKillerPath,"OculusDashKiller").ConfigureAwait(false)).Status;
}
///
/// Checks if OculusKiller exe exist and otherwise downloads the lastest release (also tries to update, if is true)
///
- public static async Task CheckKiller(bool checkUpdates = false)
+ public static async Task CheckKiller(bool checkUpdates = false)
{
- var status = await checkOculusKiller(checkUpdates);
+ var status = await checkOculusKiller(checkUpdates).ConfigureAwait(false);
OculusKillerChecked = true; //: Sets true if no exceptions
return status;
}
@@ -110,9 +89,18 @@ public static async Task CheckKiller(bool checkUpdates = false)
{
try
{
- return (new FileInfo(_oculusDashExePath).Length <= (IsOculusKillerExist? new FileInfo(_innerOculusKillerPath).Length : 1000))? //TODO: Add IsOculusExist check
- File.Exists(_oculusDashExePath)? true : null
- : false;
+ var oculusDashExeFileInfo = new FileInfo(_oculusDashExePath);
+
+ if (!oculusDashExeFileInfo.Exists) //: OculusDash.exe exist
+ {
+ var backup = new FileInfo(_oculusDashExePath + "_");
+ if (!backup.Exists) return null; //: OculusDash.exe_ exist
+ else return true;
+ }
+ else if (oculusDashExeFileInfo.Length <= (IsOculusKillerExist ? new FileInfo(_innerOculusKillerPath).Length : 1000)) //: OculusDash.exe is replaced by killer
+ return true;
+ else
+ return false; //: OculusDash.exe is ok
}
catch (Exception e)
{
@@ -123,11 +111,10 @@ public static async Task CheckKiller(bool checkUpdates = false)
public static void Break()
{
- if (!OculusKillerChecked) CheckKiller();
+ if (!OculusKillerChecked) CheckKiller().Wait();
if(IsOculusDashKilled()!= false) return;
-
File.Move(_oculusDashExePath, _oculusDashExePath + "_", true); //: Backup
- File.Move(_innerOculusKillerPath, _oculusDashExePath,true); //: Replace with Oculus Killer
+ File.Copy(_innerOculusKillerPath, _oculusDashExePath,true); //: Replace with Oculus Killer
}
public static void Restore()
diff --git a/Logic/Program.cs b/Logic/Program.cs
index 723d8ce..6f9ec7a 100644
--- a/Logic/Program.cs
+++ b/Logic/Program.cs
@@ -1,31 +1,16 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Drawing;
using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Threading.Tasks;
using System.Windows.Forms;
using InfoBox;
using Microsoft.Win32;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Titanium;
using Icon = System.Drawing.Icon;
-using System.Globalization;
-using System.Net;
-using System.Net.Http;
-using System.Resources;
-using System.Threading;
-using AngleSharp.Dom;
-using DataCollector;
using SteamVR_OculusDash_Switcher.Forms;
using SteamVR_OculusDash_Switcher.Logic;
using SteamVR_OculusDash_Switcher.Properties;
using SteamVR_OculusDash_Switcher.Properties.Localization;
-using TitaniumComparator.LogicClasses;
-
namespace SteamVR_OculusDash_Switcher
{
static partial class Program
@@ -60,6 +45,12 @@ static void Main()
Application.SetCompatibleTextRenderingDefault(true);
if (_IconsRealismLevel <0 || _IconsRealismLevel > _MaxIconsRealismLevel) _IconsRealismLevel = 1;
+ ErrorTaskDialog.InitializeDictionary(
+ LocalizationStrings.ErrorTaskDialog__OpenMicrosoftDocs,
+ LocalizationStrings.ErrorTaskDialog__Copy_to_Clipboard,
+ LocalizationStrings.ErrorTaskDialog__Open_Inner_Exception,
+ LocalizationStrings.Button__Close);
+
bool oculusBroken = false;
try
{
@@ -243,8 +234,8 @@ private static void GenerateMenuOptions(this ContextMenuStrip contextMenu)
private static void ToggleSteamVR_Click(object sender, EventArgs args)
{
- if (_SteamVr.IsBroken) RestoreSteamVR();
- else BreakSteamVR();
+ if (CurrentMode == Mode.Oculus) ToSteamVR();
+ else ToOculus();
}
private static void KillSteamVR()
@@ -255,7 +246,7 @@ private static void KillSteamVR()
{ e.ShowMessageBox(); }
}
- private static void BreakSteamVR()
+ private static void ToOculus()
{
try
{
@@ -264,7 +255,7 @@ private static void BreakSteamVR()
{
OculusDash.Restore();
}
-
+ CurrentMode = Mode.Oculus;
notifyIcon1.Icon = GetIcon();
}
catch (Exception e)
@@ -273,7 +264,7 @@ private static void BreakSteamVR()
}
}
- private static void RestoreSteamVR()
+ private static void ToSteamVR()
{
try
{
@@ -282,6 +273,9 @@ private static void RestoreSteamVR()
{
OculusDash.Break();
}
+
+ CurrentMode = Mode.SteamVR;
+
notifyIcon1.Icon = GetIcon();
}
catch (Exception e)
diff --git a/Logic/SteamVR.cs b/Logic/SteamVR.cs
index de90f9c..fe0700e 100644
--- a/Logic/SteamVR.cs
+++ b/Logic/SteamVR.cs
@@ -3,18 +3,12 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Threading.Tasks;
using System.Windows.Forms;
-using AngleSharp.Dom;
-using DataCollector;
using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SteamVR_OculusDash_Switcher.Properties.Localization;
using Titanium;
-using TitaniumComparator.LogicClasses;
namespace SteamVR_OculusDash_Switcher.Logic
{
@@ -22,7 +16,7 @@ public class SteamVR
{
public BreakMethod Method;
private static string _steamVrFolderPath;
- private static string _steamVRexeFolderPath;
+ private static string _steamVRexeFolderPath => _steamVrFolderPath.Add("\\") + @"bin\win64\";
public bool IsBroken;
public static bool IsSteamVRExeFolderExist => Directory.Exists(_steamVRexeFolderPath);
private static readonly string[] _steamVRProcesses =
@@ -57,7 +51,7 @@ public bool LocateSteamVR()
var openvrpaths = $@"c:\Users\{Environment.UserName}\AppData\Local\openvr\openvrpaths.vrpath";
_steamVrFolderPath = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 250820")?.GetValue("InstallLocation")?.ToString() ?? @"C:\Program Files (x86)\Steam\steamapps\common\SteamVR\";
- if (!Directory.Exists(_steamVrFolderPath))
+ if (!Directory.Exists(_steamVRexeFolderPath))
{
if (File.Exists(openvrpaths))
{
@@ -80,8 +74,6 @@ public bool LocateSteamVR()
methodFound = true;
} else throw new DirectoryNotFoundException("SteamVR Folder not found");
}
-
- _steamVRexeFolderPath = _steamVrFolderPath.Add("\\") + @"bin\win64\";
return !methodFound;
}
diff --git a/Logic/SteamVRMethods.cs b/Logic/SteamVRMethods.cs
index 046e7a8..ee7da99 100644
--- a/Logic/SteamVRMethods.cs
+++ b/Logic/SteamVRMethods.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using SteamVR_OculusDash_Switcher.Properties.Localization;
namespace SteamVR_OculusDash_Switcher.Logic
@@ -53,6 +49,7 @@ public override bool Equals(object? obj) =>
BreakMethod bm => bm == Value,
SteamVR svr => svr.Method == Value,
SteamVRMethod svrm => Equals(svrm),
+ DBNull => false,
_ => obj != null && (int)obj == (int)Value
};
diff --git a/Logic/Titanium.cs b/Logic/Titanium.cs
index 6b847b5..6c04636 100644
--- a/Logic/Titanium.cs
+++ b/Logic/Titanium.cs
@@ -1,13 +1,10 @@
using System;
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
+using System.IO;
using System.Linq;
-using System.Linq.Expressions;
-using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
@@ -15,15 +12,15 @@
namespace Titanium {
///
/// Just my library of small functions that makes c# programming easier. The automatization of automatization instrument
- /// Despite of the program license, THIS file is CC BY-SA
+ /// Despite of the program license, THIS file is CC BY-NC-SA
///
/// -
/// Author
/// Титан
///
///
- ///
- public static class TypesFuncs { //!21.04.2022
+ ///
+ public static class TypesFuncs { //!22.09.2022
#region Parsing
@@ -245,13 +242,14 @@ public static string ToStringT(this double Double, int Accuracy = 3) //:10.10.20
}
- public static string ToStringT(this T[] Array, string Separator = "") //:21.04.2022 Added separator parametr, replaced [foreach] by [for]
+ public static string ToStringT(this IEnumerable Array, string Separator = "") //:21.04.2022 Added separator parametr, replaced [foreach] by [for]
{
string s = "";
- for (int i = 0; i < Array.Length; i++)
+ var Count = Array.Count();
+ for (int i = 0; i < Count; i++)
{
- s += Array[i];
- if (i != Array.Length - 1) s += Separator;
+ s += Array.ElementAt(i);
+ if (i != Count - 1) s += Separator;
}
return s;
@@ -538,109 +536,49 @@ public static bool RandBool(int TrueProbability) {
#endregion
- #region List
-
- ///
- /// Случайным образом перемешивает массив
- ///
- public static List RandomShuffle(this IEnumerable list)
- {
- Random random = new Random();
- var shuffle = new List(list);
- for (var i = shuffle.Count() - 1; i >= 1; i--)
- {
- int j = random.Next(i + 1);
-
- var tmp = shuffle[j];
- shuffle[j] = shuffle[i];
- shuffle[i] = tmp;
- }
- return shuffle;
- }
-
- public static List RandomShuffle(this IEnumerable list, Random random)
- {
- var shuffle = new List(list);
- for (var i = shuffle.Count() - 1; i >= 1; i--)
- {
- int j = random.Next(i + 1);
-
- var tmp = shuffle[j];
- shuffle[j] = shuffle[i];
- shuffle[i] = tmp;
- }
- return shuffle;
- }
-
- public static List RandomList(int start, int count)
- {
- List List = new List(count);
- List Empty = new List();
- for (int i = 0; i < count; i++)
- {
- List.Add(0);
- Empty.Add(true);
- }
- Random Random = new Random();
-
- int End = start + count;
- for (int i = start; i < End;)
- {
- int Index = Random.Next(0, count); //C#-повский рандом гавно. Надо заменить чем-то
-
- if (Empty[Index])
- {
- List[Index] = i;
- Empty[Index] = false;
- i++;
-
- }
- }
-
- return List;
- }
-
- public static T Pop(this List list)
- {
- T r = list[^1];
- list.RemoveAt(list.Count-1);
- return r;
- }
-
- public static void Swap(this List list, int aIndex, int bIndex)
- {
- T value = list[aIndex];
- list[aIndex] = list[bIndex];
- list[bIndex] = value;
- }
-
- public static void Swap(this T[] list, int aIndex, int bIndex)
- {
- T value = list[aIndex];
- list[aIndex] = list[bIndex];
- list[bIndex] = value;
- }
-
- #endregion
-
- #endregion
+ #endregion
#region OtherTypeFuncs
#region Int
- static int DivRem(int dividend, int divisor, out int reminder)
+ public static bool IsOdd(this int value) => value % 2 != 0;
+ public static bool IsEven(this int value) => value % 2 == 0;
+
+ public static int DivRem(int dividend, int divisor, out int reminder)
{
int quotient = dividend / divisor;
reminder = dividend - divisor * quotient;
return quotient;
}
+
+ ///
+ /// Maxes input value be in range between MinValue and MaxValue
+ ///
+ public static int Fit(this int i, int MinValue = int.MinValue, int MaxValue = Int32.MaxValue) => i < MinValue ? MinValue : i > MaxValue ? MaxValue : i;
+
+ ///
+ /// Maxes input value be in range between 0 and MaxValue
+ ///
+ public static int FitPositive(this int i, int MaxValue = int.MaxValue) => i < 0 ? 0 : i > MaxValue ? MaxValue : i;
+ ///
+ /// Maxes input value be in range between MinValue and 0
+ ///
+ public static int FitNegative(this int i, int MinValue = int.MinValue) => i > 0 ? 0 : i < MinValue ? MinValue : i;
+
+
#endregion
#region String
+ public static bool ContainsAny(this string s, IEnumerable sequence) => sequence.Any(s.Contains);
+ public static bool ContainsAny(this string s, params string[] sequence) => sequence.Any(s.Contains); //:24.10.2022 IEnumerable replaced with params
+ public static bool ContainsAll(this string s, IEnumerable sequence) => sequence.All(s.Contains);//:24.10.2022 IEnumerable replaced with params
+
+ public static bool ContainsAll(this string s, params string[] sequence) => sequence.All(s.Contains);//:24.10.2022 IEnumerable replaced with params
+
public static int SymbolsCount(this string s)
{
int i = s.Length;
@@ -653,213 +591,288 @@ public static int SymbolsCount(this string s)
}
public static string FormatToString(this double d, int n, Positon pos, char filler = ' ') //:Ленивый и неоптимизированный способ
+ {
+ d = Math.Round(d, n);
+ string s = d.ToString();
+ if (s.Length < n) {
+ switch (pos) {
+ case Positon.left: {
+ for (int i = s.Length; i < n; i++)
{
- d = Math.Round(d, n);
- string s = d.ToString();
- if (s.Length < n) {
- switch (pos) {
- case Positon.left: {
- for (int i = s.Length; i < n; i++)
- {
- s += filler;
- }
- } break;
- case Positon.center: {
- int halfString = (n - s.Length) / 2;
- for (int i = 0; i < halfString; i++)
- {
- s=s.Insert(0, filler.ToString());
- }
- for (int i = s.Length; i < n; i++)
- {
- s += filler;
- }
- }break;
- case Positon.right: {
- for (int i = 0; i < (n - s.Length); i++)
- {
- s = s.Insert(0, filler.ToString());
- }
- }break;
- }
- }
- else if (s.Length > n) {
- int Eindex = s.LastIndexOf('E');
-
- if (Eindex > 0) { //если в строке есть Е+хх
- string E = s.TrimStart('E');
- s = s.Substring(0, n - E.Length);
- s += E;
- }
- else {
- s = s.Substring(0, n);
- }
- }
- return s;
+ s += filler;
}
-
- public static string FormatString(this string s, int n, Positon pos, char filler = ' ')
- {
- if (s.Lengthn)
+ for (int i = s.Length; i < n; i++)
{
- int Eindex = s.LastIndexOf('E');
-
- if (Eindex>0)
- { //если в строке есть Е+хх
- string E = s.TrimStart('E');
- s=s.Substring(0, n-E.Length);
- s+=E;
- }
- else
- {
- s=s.Substring(0, n);
- }
+ s += filler;
+ }
+ }break;
+ case Positon.right: {
+ for (int i = 0; i < (n - s.Length); i++)
+ {
+ s = s.Insert(0, filler.ToString());
}
- return s;
+ }break;
}
+ }
+ else if (s.Length > n) {
+ int Eindex = s.LastIndexOf('E');
- public enum Positon: byte { left,center,right}
+ if (Eindex > 0) { //если в строке есть Е+хх
+ string E = s.TrimStart('E');
+ s = s.Substring(0, n - E.Length);
+ s += E;
+ }
+ else {
+ s = s.Substring(0, n);
+ }
+ }
+ return s;
+ }
///
- /// Slices the string form Start to End not including End
+ /// Makes s.Length be equal to by adding symbols if it's too short or cutting it if it's too long
///
///
- ///
- ///
+ ///
+ /// The position of if it's too short . If it's too long, it will be always aligned Left
+ ///
+ /// Positive is right, negative is left. Will be sliced if out of range
///
- public static string Slice(this string s, int Start = 0, int End = Int32.MaxValue)
+ public static string FormatString(this string s, int FixedLength, Positon Align, char Filter = ' ', int Offset = 0)
{
- if (Start < 0) throw new ArgumentOutOfRangeException(nameof(Start),Start,null);
- if (Start > End) throw new ArgumentOutOfRangeException(nameof(Start),Start,$"start ({Start}) is be bigger than end ({End})");
- if (End > s.Length) End = s.Length;
- return s.Substring(Start, End - Start);
+ if (s.Length0? NumberOfFillerSymbols/2 : NumberOfFillerSymbols/2 +1,
+ secondHalf = NumberOfFillerSymbols-firstHalf;
+ if (NumberOfFillerSymbols.IsOdd()) Offset += (Offset > 0) ? -1 : 1;
+
+ firstHalf += Offset;
+ secondHalf -= Offset;
+ s = Filter.Multiply(firstHalf) + s + Filter.Multiply(secondHalf);
+ }
+ break;
+ case Positon.right:
+ {
+ Offset.FitNegative(NumberOfFillerSymbols);
+ NumberOfFillerSymbols += Offset;
+ s = Filter.Multiply(NumberOfFillerSymbols) + s + Filter.Multiply(Offset);
+ }
+ break;
+ }
+ }
+ else if (s.Length>FixedLength)
+ {
+ int Eindex = s.LastIndexOf('E');
+
+ if (Eindex>0)
+ { //если в строке есть Е+хх
+ string E = s.TrimStart('E');
+ s=s.Substring(0, FixedLength-E.Length);
+ s+=E;
+ }
+ else
+ {
+ s=s.Substring(0, FixedLength);
+ }
+ }
+ return s;
}
///
- /// Обрезает строку, начиная с первого появления StartsWith и заканчивая последним появлением EndsWith
+ /// Inserts between and
///
///
- /// Строка, с которой будет происходить срезание
- /// Строка, до которой будет происходить срезание
- /// Возвращать строку, если начало или конец не найдены (иначе будет возвращен null)
- /// Начинать поиск Start с конца
- /// Начинать поиск Start с конца
+ ///
+ ///
+ ///
///
- public static string Slice(this string s, string StartsWith, string EndsWith, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true)
+ ///
+ public static string Insert(this string s, string Value, int Start, int? End = null)
{
- var start = StartsWith == null? 0 : LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
-
- s = s.Slice(start);
+ int end= End?? Start;
+ if (s.IsNullOrEmpty()) return Value;
+ if (Start < 0) Start = s.Length - Start;
+ if (end < 0) end = s.Length - Start;
+ if (Start > end) Swap(ref Start, ref end);
- var end = EndsWith==null? s.Length-1 : LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
+ if (Start < 0 || Start > s.Length) throw new ArgumentException("Incorrect start " + Start, nameof(Start));
+ if (end < 0 || end > s.Length) throw new ArgumentException("Incorrect end " +end, nameof(end));
- return s.Slice(0,end);
+ return s.Slice(0,Start) + Value + s.Slice(Start);
}
- public static string SliceFromEnd(this string s, string StartsWith = null, string EndsWith = null, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true)
- {
- var end = EndsWith==null? s.Length-1 : LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
+ public enum Positon: byte { left,center,right}
- s = s.Slice(0, end);
+ ///
+ /// Slices the string form to
+ /// Supported types: , , , .
+ ///
+ /// Type of the
+ /// Type of the
+ ///
+ /// Start of the result string
+ ///
+ /// /// - : 0 (don't cut start)
+ /// - : Start index of the result string (inverse direction if negative)
+ /// - : The string inside that will be the start position of the result
+ /// - : The string inside matches Regex that will be the start position of the result
+ /// - : Условия, которым должны удовлетворять символы начала строки (по функции на 1 символ)
+ ///
+ /// End of the result string
+ ///
+ /// - : Max (don't cut end)
+ /// - : End index of the result string (inverse direction if negative)
+ /// - : The string inside that will be the end position of the result
+ /// - : The string inside matches Regex that will be the end position of the result
+ /// - : Условия, которым должны удовлетворять символы конца строки (по функции на 1 символ)
+ ///
+ /// return if or not found (may be half-cutted)
+ /// if true, the last occurance of the will be searched (doesn't do anything if is )
+ /// if true, the last occurance of the will be searched (doesn't do anything if is )
+ /// Include symbols (doesn't do anything if is )
+ /// Include symbols (doesn't do anything if is )
+ ///
+ ///
+ public static string Slice(this string s, Ts? Start, Te? End, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true, bool IncludeStart = false, bool IncludeEnd = false)
+ {
+ if (s.IsNullOrEmpty())
+ if (AlwaysReturnString)
+ return null;
+ else
+ throw new ArgumentNullException(nameof(s));
- var start = StartsWith == null? 0 : LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
+ int start;
+ int end;
+ bool BasicSlice = Start is int or null && End is int or null;
- return s.Slice(start);
- }
- public static string Slice(this string s, int Start, string EndsWith, bool AlwaysReturnString = false, bool LastEnd = true)
+ switch (Start)
{
- var end = LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(Start, end);
-
+ case null:
+ start = 0;
+ break;
+ case int startIndex:
+ start = startIndex;
+ if (start < 0) start = s.Length + start; //: count from end if negative
+ if (start < 0 || start >= s.Length)
+ if (AlwaysReturnString)
+ start = 0;
+ else
+ return null;
+ break;
+ case string startsWith:
+ start = LastStart ? s.LastIndexOfEnd(startsWith) : s.IndexOfEnd(startsWith);
+ if (start < 0) start = 0;
+ if (IncludeStart) start += startsWith.Length;
+ break;
+ case Regex startRegex:
+ var match = LastStart? startRegex.Matches(s).Last() : startRegex.Match(s);
+ start = match.Index>=0?
+ (match.Index + (IncludeStart ? 0 : match.Length)) : 0;
+ break;
+ case Func[] startConditions:
+ start = startConditions?.Any()==true?
+ s.IndexOfT(startConditions, IndexOfEnd: !IncludeStart, RightDirection: !LastStart) : 0;
+ if (start < 0) start = 0;
+ break;
+ default:
+ throw new TypeInitializationException(typeof(Ts).FullName, new ArgumentException($"Type of {nameof(Start)} is not supported"));
}
- public static string Slice(this string s, string StartsWith, int End = Int32.MaxValue, bool AlwaysReturnString = false, bool LastStart = false)
- {
- var start = LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(start, End);
- }
+ if (!BasicSlice) s = s.Slice(start);
- ///
- ///
- ///
- ///
- /// Условия, которым должны удовлетворять символы начала строки (по функции на 1 символ)
- /// Условия, которым должны удовлетворять символы конца строки (по функции на 1 символ)
- /// Возвращать изначальную строку при неудачном поиске
- ///
- public static string Slice(this string s, Func[] StartConditions, Func[] EndConditions, bool AlwaysReturnString = false)
+ switch (End)
{
- if (!StartConditions.Any()) throw new ArgumentNullException(nameof(StartConditions), "Условия начальной строки не заданы");
- if (!EndConditions.Any()) throw new ArgumentNullException(nameof(EndConditions), "Условия конечной строки не заданы");
-
- var start = s.IndexOfT(StartConditions,IndexOfEnd:true);
- if (start < 0) return AlwaysReturnString? s : null;
-
- var end =s.IndexOfT(EndConditions,LastOccuarance:true);
- if (end < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(start, end);
+ case null:
+ end = s.Length;
+ break;
+ case int endIndex:
+ end = endIndex;
+ if (end < 0) end = s.Length + end; //: count from end if negative
+ if (BasicSlice && start > end) Swap(ref start, ref end);
+ if (end > s.Length) end = s.Length;
+ break;
+ case string endsWith:
+ end = (LastEnd ? s.LastIndexOf(endsWith) : s.IndexOf(endsWith));
+ if(end<0) end = s.Length;
+ if (IncludeEnd) end += endsWith.Length;
+ break;
+ case Regex endregex:
+ var match = LastEnd? endregex.Matches(s).Last() : endregex.Match(s);
+ end = match.Index>=0?
+ (match.Index + (LastEnd ? 0 : match.Length)) : 0;
+ break;
+ case Func[] endConditions:
+ end = endConditions?.Any()!=true?
+ s.IndexOfT(endConditions,IndexOfEnd: IncludeEnd, RightDirection: !LastEnd) : 0;
+ if (end < 0)
+ if (AlwaysReturnString)
+ end = s.Length-1;
+ else
+ return null;
+ break;
+ default:
+ throw new TypeInitializationException(typeof(Ts).FullName, new ArgumentException($"Type of {nameof(End)} is not supported"));
}
- public static string Slice(this string s, int Start, Func[] EndConditions, bool AlwaysReturnString = false)
- {
- if (!EndConditions.Any()) throw new ArgumentNullException(nameof(EndConditions), "Условия конечной строки не заданы");
-
- var end =s.IndexOfT(EndConditions,LastOccuarance:true);
- if (end < 0) return AlwaysReturnString? s.Slice(Start) : null;
-
- return s.Slice(Start, end);
- }
+ return BasicSlice ?
+ s.Substring(start, (end - start)) :
+ s.Slice(0, end);
+ }
+
+ ///
+ /// Removes symbols from 0 to
+ /// Supported types: , , , ;
+ ///
+ /// Type of the
+ ///
+ /// Start of the result string
+ ///
+ /// /// - : 0 (don't cut start)
+ /// - : Start index of the result string (inverse direction if negative)
+ /// - : The string inside that will be the start position of the result
+ /// - : The string inside matches Regex that will be the start position of the result
+ /// - : Условия, которым должны удовлетворять символы начала строки (по функции на 1 символ)
+ ///
+
+ /// return if or not found (may be half-cutted)
+ /// if true, the last occurance of the will be searched (doesn't do anything if is )
+ /// Include symbols (doesn't do anything if is )
+
+ ///
+ ///
+ public static string Slice(this string s, Ts? Start, bool AlwaysReturnString = false, bool LastStart = false, bool IncludeStart = false) =>
+ s.Slice(Start, int.MaxValue, AlwaysReturnString, LastStart, false, IncludeStart, false);
- public static string Slice(this string s, int Start, Regex EndRegex, bool AlwaysReturnString = false)
+ public static string SliceFromEnd(this string s, string StartsWith = null, string EndsWith = null, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true, bool IncludeStart = false, bool IncludeEnd = false) //:25.08.2022 includeStart, includeEnd
{
- var end = EndRegex.Match(s).Index;
+ var end = EndsWith==null? s.Length-1 : LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
if (end < 0) return AlwaysReturnString? s : null;
- return s.Slice(Start, end);
+ s = s.Slice(0, end);
+
+ var start = StartsWith == null? 0 : LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
+ if (start < 0) return AlwaysReturnString? s : null;
+
+ return IncludeStart? StartsWith : "" + s.Slice(start) + (IncludeEnd? EndsWith : "");
}
private static int IndexOfEnd(this string s, string s2)
@@ -872,7 +885,7 @@ private static int IndexOfEnd(this string s, string s2)
}
///
- /// Reports the position of a symbol next to last occurance of a string s2 (position after the end of s2)
+ /// Reports the position of a symbol next to last occurance of a string (position after the end of )
///
///
///
@@ -893,39 +906,39 @@ public enum DirectionEnum
Left
}
- public static int IndexOfT(this string s, Func[] Conditions, int Start = 0, int End = Int32.MaxValue, DirectionEnum Direction = DirectionEnum.Custom, bool IndexOfEnd = false, bool LastOccuarance = false)
+ public static int IndexOfT(this string s, Func[] Conditions, int Start = 0, int End = Int32.MaxValue, bool RightDirection = true, bool IndexOfEnd = false) //:22.09.22 Bugfix, deleted useless LastOccurance; Replaced DirectionEnum with bool RightDirection
{
- if (End == Int32.MaxValue) End = Direction == DirectionEnum.Left ? 0 : s.Length-1;
+ if (End == Int32.MaxValue) End = s.Length-1;
if (Start < 0) Start = s.Length + Start;
- if (Start < 0) throw new ArgumentOutOfRangeException(nameof(Start),Start,$"incorrect negative Start ({Start - s.Length}). |Start| should be ≤ s.Length ({s.Length})");
+ if (Start < 0) new ArgumentOutOfRangeException(nameof(Start),Start,$"incorrect negative Start ({Start - s.Length}). |Start| should be ≤ s.Length ({s.Length})");
if (End < 0) End = s.Length + End;
if (End < 0) throw new ArgumentOutOfRangeException(nameof(End),End,$"incorrect negative End ({End - s.Length}). |End| should be ≤ s.Length ({s.Length})");
if (End == Start) return -2;
- if (Direction == DirectionEnum.Custom)
- Direction = End > Start ? DirectionEnum.Right : DirectionEnum.Left;
- else if ((Direction == DirectionEnum.Left && End > Start) || (Direction == DirectionEnum.Right && End < Start))
+ if(RightDirection && End < Start ||
+ !RightDirection && End > Start)
Swap(ref Start, ref End);
-
- bool rightDirection = Direction == DirectionEnum.Right;
- int defaultCurMatchPos = rightDirection? 0 : s.Length-1;
+
+ int defaultCurMatchPos = RightDirection? 0 : Conditions.Length-1;
int curCondition = defaultCurMatchPos;
- int Result = -1;
+ int Result = -1;
- if (rightDirection)
+ if (RightDirection)
for (int i = Start; i < End; i++)
{
if (Conditions[curCondition](s[i]))
{
curCondition++;
- if (curCondition != Conditions.Length-1) continue;
+ if (curCondition != Conditions.Length) continue;
Result = i;
curCondition = defaultCurMatchPos;
- if(!LastOccuarance) break;
+ //if(!LastOccuarance)
+ break;
}
else
{
+ i -= curCondition;
curCondition = defaultCurMatchPos;
}
}
@@ -938,20 +951,35 @@ public static int IndexOfT(this string s, Func[] Conditions, int Star
if (curCondition != 0) continue;
Result = i;
curCondition = defaultCurMatchPos;
- if(!LastOccuarance) break;
+ //if(!LastOccuarance)
+ break;
}
else
{
+ i += ((Conditions.Length-1) - curCondition);
curCondition = defaultCurMatchPos;
}
}
- return IndexOfEnd ? Result : Result - Conditions.Length;
+ return Result = Result == -1 || IndexOfEnd ^ !RightDirection?
+ Result : (Result - Conditions.Length) +1;
}
- public static int IndexOfT(this string s, string s2, int Start = 0, int End = Int32.MaxValue, DirectionEnum Direction = DirectionEnum.Custom, bool IndexOfEnd = false, bool LastOccuarance = false)
+ ///
+ /// Return an index of (? end : start) of in
+ ///
+ ///
+ ///
+ /// Start checking from
+ /// until End
+ /// Direction of searching
+ /// Return index of end of s2 (last letter) instead of start (first letter)
+ ///
+ ///
+ ///
+ public static int IndexOfT(this string s, string s2, int Start = 0, int End = Int32.MaxValue, bool RightDirection = true, bool IndexOfEnd = false) //:22.09.22 Bugfix, deleted useless LastOccurance; Replaced DirectionEnum with bool RightDirection
{
- if (End == Int32.MaxValue) End = Direction == DirectionEnum.Left ? 0 : s.Length-1;
+ if (End == Int32.MaxValue) End = s.Length-1;
if (Start < 0) Start = s.Length + Start;
if (Start < 0) new ArgumentOutOfRangeException(nameof(Start),Start,$"incorrect negative Start ({Start - s.Length}). |Start| should be ≤ s.Length ({s.Length})");
if (End < 0) End = s.Length + End;
@@ -959,17 +987,15 @@ public static int IndexOfT(this string s, string s2, int Start = 0, int End = In
if (End == Start) return -2;
- if (Direction == DirectionEnum.Custom)
- Direction = End > Start ? DirectionEnum.Right : DirectionEnum.Left;
- else if ((Direction == DirectionEnum.Left && End > Start) || (Direction == DirectionEnum.Right && End < Start))
+ if(RightDirection && End < Start ||
+ !RightDirection && End > Start)
Swap(ref Start, ref End);
- bool rightDirection = Direction == DirectionEnum.Right;
- int defaultCurMatchPos = rightDirection? 0 : s.Length-1;
+ int defaultCurMatchPos = RightDirection? 0 : s2.Length-1;
int curMatchPos = defaultCurMatchPos;
int Result = -1;
- if (rightDirection)
+ if (RightDirection)
for (int i = Start; i < End; i++)
{
if (s[i] == s2[curMatchPos])
@@ -978,10 +1004,12 @@ public static int IndexOfT(this string s, string s2, int Start = 0, int End = In
if (curMatchPos != s2.Length) continue;
Result = i;
curMatchPos = defaultCurMatchPos;
- if(!LastOccuarance) break;
+ //if(!LastOccuarance)
+ break;
}
else
{
+ i -= curMatchPos;
curMatchPos = defaultCurMatchPos;
}
}
@@ -994,15 +1022,18 @@ public static int IndexOfT(this string s, string s2, int Start = 0, int End = In
if (curMatchPos != 0) continue;
Result = i;
curMatchPos = defaultCurMatchPos;
- if(!LastOccuarance) break;
+ //if(!LastOccuarance)
+ break;
}
else
{
+ i += ((s2.Length-1) - curMatchPos);
curMatchPos = defaultCurMatchPos;
}
}
- return IndexOfEnd? Result : Result - s2.Length;
+ return Result = Result == -1 || IndexOfEnd ^ !RightDirection?
+ Result : (Result - s2.Length) +1;
}
@@ -1030,7 +1061,7 @@ public static string Multiply(this char s, int count)
///
- /// s[..Start] + NewString + s[End..]
+ /// [..] + + s[..]
///
/// original string
/// String from 0 to Start will be added before NewString
@@ -1060,6 +1091,7 @@ public static string Replace(this string s, int Start, int? End = null, string N
else return s[..Start] + NewString;
}
+
public static string ReplaceFromLast(this string s, string OldString, string NewString, bool Exception = true)
{
if (OldString is null)
@@ -1071,24 +1103,77 @@ public static string ReplaceFromLast(this string s, string OldString, string New
return s.Replace(start, start+OldString.Length, NewString, Exception);
}
+ public static string Replace(this string s, Dictionary ReplaceRule) => s.Replace(ReplaceRule.Keys, ReplaceRule.Values);
+
+ public static string Replace(this string s, IEnumerable OldStrings, IEnumerable NewStrings)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Escapes string
+ ///
+ ///
+ /// characters need to be escaped
+ ///
+ public static string Escape(this string s, string Characters, string EscapeSymbol = "\\") //:26.08.2022
+ {
+ string result = "";
+ foreach (var c in s)
+ {
+ if (Characters.Contains(c)) result += EscapeSymbol;
+ result += c;
+ }
+
+ return result;
+ }
+
+ public static IEnumerable Add(this IEnumerable strings, string addiction, bool ToEnd = true)
+ {
+ var list = strings.ToList();
+ for (var index = 0; index < list.Count; index++)
+ {
+ list[index] = list[index].Add(addiction, ToEnd);
+ }
+
+ return list;
+ }
+
///
- /// Adds unadded part of to in the end of . "stringTest".Add("Testing") //"stringTesting" will be unchanged if is already added to "Test".Add("st") //"Test". Replacement occuts only in end "Tests".Add("Testing") //"TestsTesting"
+ /// Добавляет ту часть к , которая не содержится в конце . Например, "Test".Add("stop") = "Testop"; "Test".Add("rest") = "Testrest"
///
- /// Initial string
- /// String that should be in the end of
+ ///
+ ///
+ /// Добавить к концу строки (иначе -- к началу)
///
- public static string Add(this string s, string addiction)
+ public static string Add(this string s, string addiction, bool ToEnd = true) => ToEnd ? AddToEnd(s, addiction) : AddToStart(s, addiction); //TODO: ToEnd лучше заменить с bool на enum Position{Start,End}
+
+ private static string AddToStart(this string s, string addiction)
+ {
+ if (addiction.Length>1) throw new NotImplementedException("AddToEnd with more than 1 character isn't supported yet");
+
+ if (s[0] != addiction[0]) return addiction + s;
+ else return s;
+ }
+
+ private static string AddToEnd(this string s, string addiction)
{
+ if (s.IsNullOrEmpty()) return addiction;
int offset = 0;
- //:Searches for *addiction* in the end of the *s*
for (; offset < addiction.Length; offset++)
{
- if (s[^1] != addiction[offset]) continue;
+ if (s[^1] != addiction[offset]) continue;
+
int aPosition = offset;
- for (int sPosition = s.Length-1; sPosition >0;)
+ for (int sPosition = s.Length-1; sPosition >=0;)
{
- if (s[sPosition--] != addiction[aPosition--]) break;
+
+ if (s[sPosition--] != addiction[aPosition--])
+ {
+ Debug.Print($"{s[..(sPosition+1)]}|{s[sPosition+1]}|{s[(sPosition+2)..]} ≠ {addiction[..(aPosition+1)]}|{addiction[aPosition+1]}|{addiction[(aPosition+2)..]}");
+ break;
+ }
if (aPosition < 0)
{
return s + addiction[(offset+1)..];
@@ -1108,8 +1193,103 @@ public static string Add(this string s, string addiction)
#endregion
- #region Array
+ #region Enumerable
+
+ public static bool ContainsAny(this IEnumerable source, params T[] values) => source.Any(values.Contains);
+ public static bool ContainsAll(this IEnumerable source, params T[] values) => source.Any(values.Contains);
+ public static bool Empty(this IEnumerable s) => !s.Any();
+ public static Tgt[] ToArray(this IEnumerable source, Func Convert)
+ {
+ Tgt[] result = new Tgt[source.Count()];
+ int i = 0;
+ foreach (var s in source)
+ {
+ result[i++] = Convert(s);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Случайным образом перемешивает массив
+ ///
+ public static List RandomShuffle(this IEnumerable list)
+ {
+ Random random = new Random();
+ var shuffle = new List(list);
+ for (var i = shuffle.Count() - 1; i >= 1; i--)
+ {
+ int j = random.Next(i + 1);
+
+ var tmp = shuffle[j];
+ shuffle[j] = shuffle[i];
+ shuffle[i] = tmp;
+ }
+ return shuffle;
+ }
+
+ public static List RandomShuffle(this IEnumerable list, Random random)
+ {
+ var shuffle = new List(list);
+ for (var i = shuffle.Count() - 1; i >= 1; i--)
+ {
+ int j = random.Next(i + 1);
+
+ var tmp = shuffle[j];
+ shuffle[j] = shuffle[i];
+ shuffle[i] = tmp;
+ }
+ return shuffle;
+ }
+
+ public static List RandomList(int start, int count)
+ {
+ List List = new List(count);
+ List Empty = new List();
+ for (int i = 0; i < count; i++)
+ {
+ List.Add(0);
+ Empty.Add(true);
+ }
+ Random Random = new Random();
+
+ int End = start + count;
+ for (int i = start; i < End;)
+ {
+ int Index = Random.Next(0, count); //C#-повский рандом гавно. Надо заменить чем-то
+
+ if (Empty[Index])
+ {
+ List[Index] = i;
+ Empty[Index] = false;
+ i++;
+
+ }
+ }
+
+ return List;
+ }
+
+ public static T Pop(this List list)
+ {
+ T r = list[^1];
+ list.RemoveAt(list.Count-1);
+ return r;
+ }
+
+ public static void Swap(this List list, int aIndex, int bIndex)
+ {
+ T value = list[aIndex];
+ list[aIndex] = list[bIndex];
+ list[bIndex] = value;
+ }
+ public static void Swap(this T[] list, int aIndex, int bIndex)
+ {
+ T value = list[aIndex];
+ list[aIndex] = list[bIndex];
+ list[bIndex] = value;
+ }
public static int IndexOf(this T[] array, T value) => Array.IndexOf(array, value);
public static T[][] Split(this T[] array, int arraysCount)
@@ -1189,7 +1369,7 @@ public static T[] ReduceDimension(this T[][] Arrays)
return res;
}
- public static string ToStringLine(this T[] Array, string Separator = " ")
+ public static string ToStringLine(this IEnumerable Array, string Separator = " ")
{
string result = "";
foreach (var el in Array)
@@ -1200,7 +1380,7 @@ public static string ToStringLine(this T[] Array, string Separator = " ")
return result[..^Separator.Length];
}
- public static string ToStringLine(this List Array, string Separator = " ")
+ public static string ToStringLine(this IEnumerable Array, string Separator, string LastSeparator)
{
string result = "";
foreach (var el in Array)
@@ -1240,13 +1420,35 @@ public static List AddRangeAndGet(this List list, List summand)
return list;
}
- public static string Remove(this string S, string RemovableString, StringComparison ComparisonType = StringComparison.Ordinal)
+ ///
+ /// Removes (? first : last) occurance of
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static string Remove(this string S, string RemovableString, bool FromLeft = true, StringComparison ComparisonType = StringComparison.Ordinal)
{
if (RemovableString is null or "") return S;
- int startPos = S.IndexOf(RemovableString, ComparisonType);
+ int startPos = FromLeft? S.IndexOf(RemovableString) : S.LastIndexOf(RemovableString);
return startPos == -1 ? S : S.Remove(startPos, RemovableString.Length);
}
+ public static string RemoveFrom(this string Source, TypesFuncs.Side FromWhere = Side.End, params string[] RemovableStrings)
+ {
+ foreach (var rem in RemovableStrings)
+ Source = Source.RemoveFrom(FromWhere, rem);
+ return Source;
+ }
+
+ public static string RemoveFrom(this string Source, Side FromWhere, string RemovableString)
+ {
+ if (FromWhere!= Side.End && Source.StartsWith(RemovableString)) Source = Source.Slice(RemovableString.Length);
+ if (FromWhere!= Side.Start && Source.EndsWith(RemovableString)) Source = Source.Slice(0, -RemovableString.Length);
+ return Source;
+ }
+
public static string RemoveAll(this string S, string RemovableString, StringComparison ComparisonType = StringComparison.Ordinal)
{
if (RemovableString is null or "") return S;
@@ -1260,6 +1462,46 @@ public static string RemoveAll(this string S, string RemovableString, StringComp
}
}
+ public static string RemoveAll(this string S, string[] RemovableStrings, StringComparison ComparisonType = StringComparison.Ordinal)
+ {
+ foreach (var s in RemovableStrings)
+ {
+ S = S.RemoveAll(s, ComparisonType);
+ }
+
+ return S;
+ }
+
+ public enum Side
+ {
+ Start,
+ End,
+ Both
+ }
+
+ public static string RemoveAllFrom(this string S, string RemovableChars, Side FromWhere = Side.Both, StringComparison ComparisonType = StringComparison.Ordinal)
+ {
+ int start = 0, end = 0;
+
+ if (FromWhere != Side.End)
+ foreach (var C in S)
+ {
+ if (RemovableChars.Contains(C)) start++;
+ else break;
+ }
+
+ if (FromWhere != Side.Start)
+ for (int i = S.Length -1; i >=0; i--)
+ {
+ if (RemovableChars.Contains(S[i])) end++;
+ else break;
+ }
+
+ return S[start..^end];
+ }
+
+ public static bool AllEquals(this IEnumerable array) => array.All(x => Equals(array.First(), x));
+
#endregion
#region Size
@@ -1295,21 +1537,59 @@ public enum Dimension
}
#endregion
- #region Image
+ #region Regex
-
- public static Image Resize(this Image i, int NewDimensionValue, Dimension FixedDimension = Dimension.Height)
+ public static bool IsMatchT(this Regex r, string s, int start = 0) => s != null && r.IsMatch(s, start);
+ public static bool IsMatchAny(this IEnumerable r, string s, int start = 0) => s != null && r.Any(x => x.IsMatch(s));
+ public static bool IsMatchAll(this IEnumerable r, string s, int start = 0) => s != null && r.All(x => x.IsMatch(s));
+ public static Regex Reverse(this Regex r)
+ {
+ var regStr = r.ToString();
+ return regStr.StartsWith(@"^((?!") && regStr.EndsWith(@").)*")? new Regex(regStr[5..^4]) : new Regex(@"^((?!" + r + @").)*");
+ }
+
+ public static List ReverseRegexes(this List r)
+ {
+ for (int i = 0; i < r.Count; i++)
+ {
+ r[i] = Reverse(r[i]);
+ }
+
+ return r;
+ }
+
+ ///
+ /// Swaps "equal" mode to "contains" mode (Добавляет $/^ в начало/конец, если их нет; Убирает их, если они есть)
+ ///
+ ///
+ ///
+ internal static Regex InvertRegex(string S)
{
- return i == null? null : new Bitmap(i, i.Size.Resize(NewDimensionValue, FixedDimension));
+ bool anyStart = S.StartsWith("^");
+ bool anyEnd = S.EndsWith("$");
+ S = anyStart ? S[1..] : $"^{S}";
+ S = anyEnd ? S[..^1] : $"{S}$";
+ return new Regex(S);
}
+
#endregion
- #region Color
+ #region Dictionary
- static Color Change(this Color c, byte? A = null, byte? R = null, byte? G = null, byte? B = null) => Color.FromArgb(A?? c.A, R??c.R, G??c.G, B??c.B);
+ /*public static Dictionary Reverse(this Dictionary source)
+ {
+ for (int i = 0; i < source.Count; i++)
+ {
+ source.
+ }
+ }*/
#endregion
+ #region Color
+
+ static Color Change(this Color c, byte? A = null, byte? R = null, byte? G = null, byte? B = null) => Color.FromArgb(A?? c.A, R??c.R, G??c.G, B??c.B);
+
#region Universal Type
public static void Swap(ref T a, ref T b)
@@ -1333,5 +1613,306 @@ public static bool IsDefault(this T value) where T : struct
#endregion
+ #region Process
+
+ public static void KillProcesses(string? Path = null, string? Name = null)
+ {
+ List processes;
+ Name ??= Path?.Slice(new[] { new Func(x => x is '\\' or '/') }, LastStart:true);
+ try
+ {
+ processes = (
+ from proc in Name == null ? Process.GetProcesses() : Process.GetProcessesByName(Name)
+ where Path == null || proc.MainModule.FileName == Path
+ select proc
+ ).ToList();
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Error while gathering processes", e);
+ }
+
+ var Exceptions = new List();
+
+ foreach (var proc in processes)
+ {
+ try
+ {
+ proc.Kill();
+ }
+ catch (Exception e)
+ {
+ Exceptions.Add(new InvalidOperationException($"Can't kill process {proc.ProcessName}", e));
+ }
+ }
+
+ if (Exceptions.Count > 0) throw new AggregateException(Exceptions);
+ }
+
+ #endregion
+
+ #endregion
+ }
+
+ public static class IO
+ {
+ ///
+ /// Copies all files, directories, subdirectories and it's contant to the new folder
+ ///
+ ///
+ ///
+ ///
+ /// All paths should end on "\" and contains only "\" (not "/)
+ public static void CopyAll(string SourcePath, string TargetPath, bool KillRelatedProcesses = false, List ExceptList = null, bool DisableSyntaxCheck = false)
+ {
+ ExceptList ??= new List();
+ var ErrorList = new List();
+ if (!DisableSyntaxCheck)
+ {
+ SourcePath = SourcePath.Replace("/", "\\").Add("\\");
+ TargetPath = TargetPath.IsNullOrEmpty()? "" : TargetPath.Replace("/", "\\").Add("\\");
+ }
+
+ //Now Create all of the directories
+ foreach (string dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories))
+ {
+ if (ExceptList.IsMatchAny(dirPath)) continue;
+ try
+ {
+ Directory.CreateDirectory(dirPath.Replace(SourcePath, TargetPath));
+ }
+ catch (Exception e)
+ {
+ ErrorList.Add(e);
+ }
+
+ }
+
+ //Copy all the files & Replaces any files with the same name
+ foreach (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories))
+ {
+ if (ExceptList.IsMatchAny(newPath)) continue;
+ try
+ {
+ var destination = newPath.Replace(SourcePath, TargetPath);
+ if (KillRelatedProcesses && destination.EndsWith(".exe"))
+ TypesFuncs.KillProcesses(Path: destination);
+ File.Copy(newPath, destination , true);
+ }
+ catch (Exception e)
+ {
+ ErrorList.Add(e);
+ }
+
+ }
+
+ if (ErrorList.Count > 0) throw new AggregateException("Unable to copy files" ,ErrorList);
+ }
+
+ public static void RemoveAll(string FolderPath, bool RemoveSelf = true, List? ExceptList = null)
+ {
+ var ErrorList = new List();
+
+ foreach (var dir in Directory.GetDirectories(FolderPath))
+ {
+ try
+ {
+ if(ExceptList?.IsMatchAny(dir)?? false) continue;
+ RemoveAll(dir, ExceptList:ExceptList);
+ }
+ catch (Exception e)
+ {
+ ErrorList.Add(e);
+ }
+ }
+
+ foreach (var file in Directory.GetFiles(FolderPath))
+ {
+ if(ExceptList?.IsMatchAny(file)?? false) continue;
+ File.Delete(file);
+ }
+
+ if (RemoveSelf)
+ try { Directory.Delete(FolderPath, false);}
+ catch (Exception e) {ErrorList.Add(e);}
+
+ if (ErrorList.Count > 0) throw new AggregateException("Unable to copy files" ,ErrorList);
+ }
+
+ ///
+ /// Renames all files in the Directory (not recursive)
+ ///
+ ///
+ /// Function where input is file's name (not path) and the output is new file's name
+ /// Regular expression of filePATHs that won't be renamed
+ public static void RenameAll(string FolderPath, Func Rename, List? ExceptList = null)
+ {
+ ExceptList ??= new List();
+ foreach (var file in Directory.GetFiles(FolderPath))
+ {
+ if(ExceptList.IsMatchAny(file)) continue;
+
+ var fileInfo = new FileInfo(file);
+ var path = fileInfo.Directory.FullName;
+ var fileName = fileInfo.Name;
+ File.Move(file,Path.Combine(path, Rename(fileName)));
+ }
+ }
+
+ public static void CopyAllTo(this DirectoryInfo di, string TargetPath, bool KillRelatedProcesses = false, List ExceptList = null, bool DisableSyntaxCheck = false)
+ {
+ CopyAll(di.FullName, TargetPath, KillRelatedProcesses, ExceptList, DisableSyntaxCheck);
+ }
+
+ public static void MoveAllTo(string SourcePath, string TargetPath, bool DeleteSourceDir = true, bool KillRelatedProcesses = false, List ExceptList = null, bool DisableSyntaxCheck = false) => new DirectoryInfo(SourcePath).MoveAllTo(TargetPath, DeleteSourceDir, KillRelatedProcesses, ExceptList, DisableSyntaxCheck);
+
+ public static void MoveAllTo(this DirectoryInfo di, string TargetPath, bool DeleteSourceDir = true, bool KillRelatedProcesses = false, List ExceptList = null, bool DisableSyntaxCheck = false)
+ {
+ var sourcePath = di.FullName;
+ CopyAll(sourcePath,TargetPath,KillRelatedProcesses, ExceptList, DisableSyntaxCheck);
+ if (DeleteSourceDir) Directory.Delete(sourcePath, true);
+ else
+ {
+ foreach (var dir in di.GetDirectories())
+ {
+ if (ExceptList.IsMatchAny(dir.FullName))
+ dir.Delete(true);
+ }
+ }
+ }
+ }
+
+ public static class ClassicFuncs
+ {
+ public static bool IsNullOrEmpty(this string s) => string.IsNullOrEmpty(s);
+
+ public static bool IsNullOrWhiteSpace(this string s) => string.IsNullOrWhiteSpace(s);
+ ///
+ /// Retrieves reference to specified string
+ ///
+ ///
+ /// A reference to s if it is in the common language runtime intern pool; otherwise null
+ public static string IsInterned(this string s) => string.IsInterned(s);
+
+ }
+
+ public static class Classes
+ {
+ public class FileSize
+ {
+ private long longSize;
+
+ public double Size;
+ public SizeUnit Unit;
+
+ public enum SizeUnit
+ {
+ Bit,
+ Byte,
+ KiloByte,
+ MegaByte,
+ GigaByte,
+ TeraByte,
+ PetaByte,
+ ExaByte,
+ ZettaByte,
+ YottaByte,
+ KiloBit,
+ MegaBit,
+ GigaBit,
+ TeraBit,
+ PetaBit,
+ ExaBit,
+ ZettaBit,
+ YottaBit
+ }
+
+ private static string[][] UnitNames = new[]
+ {
+ new[] { "bit" },
+ new[] { "byte", "b" },
+ new[] { "kilobyte", "kb" },
+ new[] { "megabyte", "mb" },
+ new[] { "gigabyte", "gb" },
+ new[] { "terabyte", "tb" },
+ new[] { "petabyte", "pb" },
+ new[] { "exabyte", "eb" },
+ new[] { "zettabyte", "zb" },
+ new[] { "yottabyte", "yb" },
+ new[] { "kilobit", "kbit" },
+ new[] { "megabit", "mbit" },
+ new[] { "gigabit", "gbit" },
+ new[] { "terabit", "tbit" },
+ new[] { "petabit", "pbit" },
+ new[] { "exabit", "ebit" },
+ new[] { "zettabit", "zbit" },
+ new[] { "yottabit", "ybit" }
+ };
+
+ private void CalculateLongSize()
+ {
+ int intUnit = (int)Unit;
+ longSize = (long)(
+ (SizeUnit)(Size * (double)Unit) ==
+ SizeUnit.Bit ? 1 :
+ Unit == SizeUnit.Byte ? 8 :
+ Math.Pow(2, (intUnit - 2) % 8 + 1) * (Unit > SizeUnit.YottaByte ? 1 : 8)
+ );
+ }
+
+ private static string getUnitName(SizeUnit SU) => UnitNames[(int)SU][0];
+
+ private static SizeUnit getSizeUnit(string UnitName, bool strictlyEqual = false)
+ {
+ var lowerUnitName = UnitName.ToLower();
+
+ for (int i = UnitNames.Length-1; i >=0; i--)
+ {
+ //Debug.Write(UnitNames[i].ToStringT(", "));
+ if (strictlyEqual? UnitNames[i].Contains(lowerUnitName) : UnitNames[i].Any(lowerUnitName.Contains))
+ return (SizeUnit)i;
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(UnitName), "can't find unit named " + UnitName);
+ }
+
+ public FileSize(long BitsCount)
+ {
+ longSize = BitsCount;
+ Size = BitsCount;
+ Unit = 0;
+ if (BitsCount < 8) return;
+ Size /= 8;
+ Unit++;
+ for (; Size > 1024 && Unit
- /// Just my library of small functions that makes c# programming easier. The automatization of automatization instrument
- /// Despite of the program license, THIS file is CC BY-SA
+ /// Just my library of small functions that makes c# WinForms programming easier.
+ /// Despite of the program license, THIS file is CC BY-NC-SA
///
/// -
/// Author
@@ -23,1315 +21,393 @@ namespace Titanium {
///
///
///
- public static class TypesFuncs { //!21.04.2022
-
-
- #region Parsing
-
- #region IsType
- public static bool IsDigit(this char c) => c >= '0' && c <= '9';
-
- public static bool IsDoubleT(this char c) => (c >= '0' && c <= '9')||( c == '.' || c == ','||c=='-');
- #endregion
-
- #region ToType
- #region Int
-
-
- ///
- /// Преобразует число в char в Int
- ///
- ///
- /// Число, если содержимое Char – число:
- /// -1 в противном случае
- public static int ToIntT(this char ch) =>
- ch is >= '0' and <= '9'?
- ch-'0' : -1;
-
- ///
- /// "534 Убирает все лишние символы и читает Int. 04" => 53404. Максимально оптимизирован, даже лучше стандартного
- ///
- ///
- /// Может ли число быть отрицательным (если нет, то - будет игнорироваться, иначе он будет учитываться только если стоит рядом с числом)
- /// If true, stops parsing if int already found, but current symbol isn't a number
- /// Возвращаемое значение при исключении (если не указывается, то при исключении... вызывается исключение
- /// Числа, если они содержаться в строке
- public static int ToIntT(this string str, bool CanBeNegative = true, bool StopIfNumberEnded = false, int? ExceptionValue = null) //:16.05.2022 removed reduntant ischar check
- {
- int Number = 0;
- bool isContainsNumber = false;
- bool negative = false;
- foreach (var ch in str)
- {
- if (CanBeNegative&&!isContainsNumber) //:multiple ifs each cycle isn't affects perfomance; CanBeNegative не проверялось
- {
- if (ch == '-') negative = true;
- else if (ch != ' ') negative = false;
- }
- if (ch.IsDigit())
- {
- isContainsNumber = true;
- if (Number > int.MaxValue / 10) return negative ? int.MinValue : int.MaxValue; //:none or positive perfomance effect
- //TODO: make options for ValueOutOfRange ↑ – exceptoin; custom value; min/max value (current); overflow (system default)
- Number = Number * 10 + (ch - '0');
- } else if(StopIfNumberEnded && isContainsNumber) break;
- }
-
- if (!isContainsNumber)
- {
- if (ExceptionValue == null)
- {
- throw new ArgumentException("Строка не содержит числа");
- }
- else return (int)ExceptionValue;
- }
-
- return negative? -Number:Number;
- }
-
- public static long ToLongT(this string str, bool CanBeNegative = true, bool StopIfNumberEnded = false, long? ExceptionValue = null)
- {
- long Number = 0;
- bool isContainsNumber = false;
- bool negative = false;
- foreach (var ch in str)
- {
- if (CanBeNegative&&!isContainsNumber) //:multiple ifs each cycle isn't affects perfomance; CanBeNegative не проверялось
- {
- if (ch == '-') negative = true;
- else if (ch != ' ') negative = false;
- }
- if (ch.IsDigit())
- {
- isContainsNumber = true;
- if (Number > long.MaxValue / 10) return negative ? long.MinValue : long.MaxValue; //:none or positive perfomance effect
- //TODO: make options for ValueOutOfRange ↑ – exceptoin; custom value; min/max value (current); overflow (system default)
- Number = Number * 10 + (ch - '0');
- } else if(StopIfNumberEnded && isContainsNumber) break;
- }
-
- if (!isContainsNumber)
- {
- if (ExceptionValue == null)
- {
- throw new ArgumentException("Строка не содержит числа");
- }
- else return (long)ExceptionValue;
- }
-
- return negative? -Number:Number;
- }
-
-
- public static int? ToNIntT(this string str, bool CanBeNegative = true, bool StopIfNumberEnded = false) //:08.10.2021 new func
- {
- try
- {
- return ToIntT(str, CanBeNegative,StopIfNumberEnded);
- }
- catch (Exception)
- {
- return null;
- }
- }
-
-
- ///
- /// Searches for INT in string. Throws IndexOutOfRangeException if no any int found in this string.
- ///
- ///
- ///
- /// first INT number found in string
- public static int FindInt(this string str, char thousandSeparator = ' ') //! legacy Obsolete
- {
- int end = 0, start = 0;
- bool minus = false;
- while (!str[start].IsDigit())
- {
- minus = str[start] == '-';
- start++;
- }
-
- end = minus ? start - 1 : start;
-
- do
- {
- end++;
- } while ((str[end].IsDigit() || str[end] == thousandSeparator) && end < str.Length - 1);
-
- return Convert.ToInt32(str.Substring(start,end-start).Replace(thousandSeparator.ToString(), ""), new CultureInfo("en-US", true));
- }
- public static int FindIntBetween(this string MainStr, string LeftStr, string RightStr = null)
- {
- if (RightStr == null) RightStr = LeftStr;
- int right = MainStr.IndexOf(RightStr),
- left = MainStr.LastIndexOf(LeftStr, 0, right - 1);
- int number;
-
- do
- { //TODO: Сначала искать IndexOf Right, потом LastIndexOf Left,
- if (int.TryParse(MainStr.Substring(left+1,right-(left+1)), out number)) return number;
- right = MainStr.IndexOf(RightStr);
- left = MainStr.LastIndexOf(LeftStr, left, (right - left) - 1);
- } while (left > 0 && right > 0);
-
- return -1;
- }
-
- #endregion
-
- #region String
-
- ///
- /// Int to subscript numbers string
- ///
- ///
- ///
- public static string ToIndex(this int number)
- {
- string num = number.ToString();
- string index = "";
-
- for (int i = 0; i < num.Length; i++) {
- if (num[i] == '1') index += '₁';
- if (num[i] == '2') index += '₂';
- if (num[i] == '3') index += '₃';
- if (num[i] == '4') index += '₄';
- if (num[i] == '5') index += '₅';
- if (num[i] == '6') index += '₆';
- if (num[i] == '7') index += '₇';
- if (num[i] == '8') index += '₈';
- if (num[i] == '9') index += '₉';
- if (num[i] == '0') index += '₀';
- }
- return index;
- }
-
- public static string ToVisibleString(this string s) //!03.10.2021
- {
- string a = "";
- foreach (char c in s)
- {
- if (!char.IsControl(c)) a += c;
- }
-
- return a;
- }
-
-
- ///
- /// Преобразовывает string в double, обрезая дробную часть до момента, когда начинаются нули
- ///
- ///
- ///
- ///
- public static string ToStringT(this double Double, int Accuracy = 3) //:10.10.2021 Created
- {
- var String = Double.ToString(CultureInfo.InvariantCulture); //: Пока я не умею преобразовывать double в String с минимально возможными затратами самостоятельно
- var temp = String.Split('.');
- if (temp.Length == 1)
- {
- return temp[0];
- }
- else
- {
- string intPart = temp[0], decPart = temp[1];
- int superfluity = decPart.IndexOf('0'.Multiply(Accuracy)); //TODO: вместо нулей можно пробегать по строке, пока символ не начнет повторятся несколько раз
- if (superfluity == -1) return String;
-
- decPart = decPart.Slice(0, superfluity);
- return intPart + "." + decPart;
- }
-
- }
-
- public static string ToStringT(this T[] Array, string Separator = "") //:21.04.2022 Added separator parametr, replaced [foreach] by [for]
- {
- string s = "";
- for (int i = 0; i < Array.Length; i++)
- {
- s += Array[i];
- if (i != Array.Length - 1) s += Separator;
- }
-
- return s;
- }
-
- public static string ToStringT (this IDictionary Dictionary, bool Vertical = true, string ItemSeparator = default, string PairSeparator = "\n", string BeforePair = null, string AfterPair = null)
- {
- ItemSeparator??= Vertical? " = " : ", ";
-
- if(Vertical) return BeforePair + string.Join(PairSeparator, Dictionary.Select(kv => kv.Key + ItemSeparator + kv.Value).ToArray()) + AfterPair;
- else
- {
- string result = BeforePair;
- foreach (var key in Dictionary.Keys)
- {
- result += key + ItemSeparator;
- }
-
- result = result.Replace(-ItemSeparator.Length,null,AfterPair + PairSeparator + BeforePair);
-
- foreach (var value in Dictionary.Values)
- {
- result += value + ItemSeparator;
- }
-
- return result + AfterPair;
- }
-
- }
-
-
- #region Bytes
-
- ///
- /// Reads String and parses to Short until meets a letter
- ///
- ///
- ///
-
- public static string ToHex(this byte[] bytes)
- {
- char[] c = new char[bytes.Length * 2];
-
- byte b;
-
- for (int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
- {
- b = ((byte)(bytes[bx] >> 4));
- c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
-
- b = ((byte)(bytes[bx] & 0x0F));
- c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
- }
-
- return new string(c);
- }
+ public static class Forms
+ {
+ /// -
+ /// source
+ /// SmirnoFF.Oleg
+ ///
+ public static T Clone(this T controlToClone)
+ where T : Control
+ {
+ PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
- #endregion
+ T instance = Activator.CreateInstance();
- #endregion
-
- #region Double
-
- ///
- /// "534 Убирает все лишние символы и читает double. 0.4" => 5340.4
- ///
- ///
- ///
- ///
- /// Может ли нуль целой части быть опущен (".23" вместо "0.23")
- ///
- /// Разделитель целой и дробной части
- ///
- ///
- public static double ToDoubleT(this string str, bool CanBeNegative = true, bool StopIfNumberEnded = false, bool CanBeShortcuted = true, bool DotShouldBeAttachedToNumber = true, char Separator = '.', double? ExceptionValue = Double.NaN) //:23.05.2022 Behaviour merged from ToIntT()
- {
- double Double = 0;
- bool? IntPart = true;
- int FractionalPart = -1;
- bool isContainsDouble = false;
- bool negative = false;
- foreach (var ch in str)
- {
- if (IntPart == true)
- {
- if (CanBeNegative&&!isContainsDouble && ch == '-') negative = true; //:multiple ifs per cycle isn't affects perfomance; CanBeNegative не проверялось
- else if (!isContainsDouble && ch != ' ') negative = false;
- else if (ch.IsDigit())
- {
- if (Double > double.MaxValue / 10) return negative ? double.MinValue : double.MaxValue;
- //TODO: make options for ValueOutOfRange ↑ – exceptoin; custom value; min/max value (current); overflow (system default)
- Double = Double * 10 + (ch - '0');
- isContainsDouble = true;
- }
- else if (ch == Separator) IntPart = null; //: Состояние квантовой запутанности. Целая часть и закончилась или нет одновременно. Ну а на самом деле просто чтобы не парсил точку или запятую в предложении как разделитель
- else if(StopIfNumberEnded && isContainsDouble) break;
- }
- else
- {
- if (ch.IsDigit())
- {
- if(FractionalPart==15) break;
- IntPart = false;
- //:на случай строки вроде ".23" (=="0.23")
- if (!isContainsDouble && !CanBeShortcuted)
- {
- Double = Double * 10 + ch.ToIntT();
- isContainsDouble = true;
- IntPart = true;
- continue;
- }
- Double += ch.ToIntT()*Math.Pow(10, FractionalPart--);
- }
- else if (IntPart == null && DotShouldBeAttachedToNumber) IntPart = true;
- else if(StopIfNumberEnded && isContainsDouble) break;
- }
- }
-
- if (!isContainsDouble)
- {
- if (ExceptionValue == null)
- {
- throw new ArgumentException("Строка не содержит числа");
- }
- else return (int)ExceptionValue;
- }
- return negative? -Double:Double;
- }
-
- public static double? ToNDoubleT(this string str, char Separator = '.', bool CanBeNegative = true, bool CanBeShortcuted = true, bool DotShouldBeAttachedToNumber = true, bool StopIfNumberEnded = false) //:08.10.2021 new func
+ foreach (PropertyInfo propInfo in controlProperties)
+ {
+ if (propInfo.CanWrite)
{
- try
- {
- return ToDoubleT(str, CanBeNegative, StopIfNumberEnded, CanBeShortcuted, DotShouldBeAttachedToNumber, Separator);
- }
- catch (Exception)
- {
- return null;
- }
+ if(propInfo.Name != "WindowTarget")
+ propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null);
}
+ }
+ return instance;
+ }
- #endregion
-
- #region Float
-
- public static float FindFloat(this string str, char DecimalSeparator = '.', char thousandSeparator = ' ')
- {
- int start = 0;
- bool minus = false;
- while (!str[start].IsDigit())
- {
- minus = str[start] == '-';
- start++;
- }
-
- int end = minus ? start - 1 : start;
- do
- {
- end++;
- } while ((str[end].IsDigit() || str[end] == thousandSeparator || str[end] == DecimalSeparator) && end < str.Length - 1);
-
- return Convert.ToSingle(str.Substring(start, end - start).Replace(DecimalSeparator, '.').Replace(thousandSeparator.ToString(), ""), new CultureInfo("en-US", true));
- }
-
-
- #endregion
-
- #region Short
-
- public static short ReadShortUntilLetter(this string str)
- {
- short Short = 0;
- foreach (var ch in str)
- {
- if (ch.IsDigit())
- {
- Short = (short)(Short* 10 + (short)ch);
- }
- else break;
- }
-
- return Short;
- }
-
- #endregion
-
- #region Bool
-
- public static bool ToBool(this string S)
- {
- return S.ToLower() is "true" or "yes" or "да" or "1";
- }
-
- public static string ToRuString(this bool Bool)
- {
- return Bool? "Да" : "Нет";
- }
-
- public static bool RandBool(int TrueProbability) {
- Random rand = new Random((int)DateTime.Now.Ticks);
- return rand.Next() <= TrueProbability;
- }
-
- #endregion
-
- #region Array
-
- public static double[,] ToDoubleT(this string[,] Strings, char Separator = '.')
- {
- int d0 = Strings.GetLength(0), d1 = Strings.GetLength(1);
- double[,] doubles = new double[d0, d1];
- for (int i = 0; i < d0; i++)
- {
- for (int j = 0; j < d1; j++)
- {
- doubles[i, j] = Strings[i, j].ToDoubleT(Separator:Separator);
- }
- }
-
- return doubles;
- }
-
- public static string[,] ToStringT(this double[,] Doubles, string Format)
- {
- int d0 = Doubles.GetLength(0), d1 = Doubles.GetLength(1);
- string[,] strings = new string[d0, d1];
- for (int i = 0; i < d0; i++)
- {
- for (int j = 0; j < d1; j++)
- {
- strings[i, j] = Doubles[i, j].ToString(Format);
- }
- }
-
- return strings;
- }
-
- public static string[,] ToStringMatrix(this double[,] Doubles)
- {
- int d0 = Doubles.GetLength(0), d1 = Doubles.GetLength(1);
- string[,] strings = new string[d0, d1];
- for (int i = 0; i < d0; i++)
- {
- for (int j = 0; j < d1; j++)
- {
- strings[i, j] = Doubles[i, j].ToString();
- }
- }
-
- return strings;
- }
-
- public static T[,,] ToSingleArray(this T[][,] list)
- {
- int[] dimensions = new[] { list.Length, list[0].GetLength(0), list[0].GetLength(1) };
-
- T[,,] result = new T[dimensions[0],dimensions[1],dimensions[2]];
-
- try
- {
-
- for (int i = 0; i < dimensions[0]; i++)
- {
- for (int j = 0; j < dimensions[1]; j++)
- {
- for (int k = 0; k < dimensions[2]; k++)
- {
- result[i, j, k] = list[i][j, k];
- }
- }
- }
-
- }
- catch (ArgumentOutOfRangeException e)
- {
- throw new ArgumentException("iternal arrays' dimensions should be the same", e);
- }
-
- return result;
- }
-
- #endregion
-
- #endregion
-
- #region List
-
- ///
- /// Случайным образом перемешивает массив
- ///
- public static List RandomShuffle(this IEnumerable list)
- {
- Random random = new Random();
- var shuffle = new List(list);
- for (var i = shuffle.Count() - 1; i >= 1; i--)
- {
- int j = random.Next(i + 1);
-
- var tmp = shuffle[j];
- shuffle[j] = shuffle[i];
- shuffle[i] = tmp;
- }
- return shuffle;
- }
-
- public static List RandomShuffle(this IEnumerable list, Random random)
- {
- var shuffle = new List(list);
- for (var i = shuffle.Count() - 1; i >= 1; i--)
- {
- int j = random.Next(i + 1);
-
- var tmp = shuffle[j];
- shuffle[j] = shuffle[i];
- shuffle[i] = tmp;
- }
- return shuffle;
- }
-
- public static List RandomList(int start, int count)
- {
- List List = new List(count);
- List Empty = new List();
- for (int i = 0; i < count; i++)
- {
- List.Add(0);
- Empty.Add(true);
- }
- Random Random = new Random();
-
- int End = start + count;
- for (int i = start; i < End;)
- {
- int Index = Random.Next(0, count); //C#-повский рандом гавно. Надо заменить чем-то
-
- if (Empty[Index])
- {
- List[Index] = i;
- Empty[Index] = false;
- i++;
-
- }
- }
-
- return List;
- }
-
- public static T Pop(this List list)
- {
- T r = list[^1];
- list.RemoveAt(list.Count-1);
- return r;
- }
- public static void Swap(this List list, int aIndex, int bIndex)
- {
- T value = list[aIndex];
- list[aIndex] = list[bIndex];
- list[bIndex] = value;
- }
-
- public static void Swap(this T[] list, int aIndex, int bIndex)
- {
- T value = list[aIndex];
- list[aIndex] = list[bIndex];
- list[bIndex] = value;
- }
-
- #endregion
-
- #endregion
-
-
- #region OtherTypeFuncs
-
- #region Int
-
- static int DivRem(int dividend, int divisor, out int reminder)
+ /// -
+ /// source
+ /// Stuart Helwig
+ ///
+ public static void CopyPropertiesTo(this Control sourceControl, Control targetControl)
+ {
+ // make sure these are the same
+ if (sourceControl.GetType() != targetControl.GetType())
{
- int quotient = dividend / divisor;
- reminder = dividend - divisor * quotient;
- return quotient;
+ throw new ArgumentException("Incorrect control types");
}
- #endregion
-
- #region String
-
- public static int SymbolsCount(this string s)
+ foreach (PropertyInfo sourceProperty in sourceControl.GetType().GetProperties())
{
- int i = s.Length;
- foreach (var c in s)
+ object newValue = sourceProperty.GetValue(sourceControl, null);
+
+ MethodInfo mi = sourceProperty.GetSetMethod(true);
+ if (mi != null)
{
- if (char.IsControl(c)) i--;
+ sourceProperty.SetValue(targetControl, newValue, null);
}
-
- return i;
}
+ }
- public static string FormatToString(this double d, int n, Positon pos, char filler = ' ') //:Ленивый и неоптимизированный способ
- {
- d = Math.Round(d, n);
- string s = d.ToString();
- if (s.Length < n) {
- switch (pos) {
- case Positon.left: {
- for (int i = s.Length; i < n; i++)
- {
- s += filler;
- }
- } break;
- case Positon.center: {
- int halfString = (n - s.Length) / 2;
- for (int i = 0; i < halfString; i++)
- {
- s=s.Insert(0, filler.ToString());
- }
- for (int i = s.Length; i < n; i++)
- {
- s += filler;
- }
- }break;
- case Positon.right: {
- for (int i = 0; i < (n - s.Length); i++)
- {
- s = s.Insert(0, filler.ToString());
- }
- }break;
- }
- }
- else if (s.Length > n) {
- int Eindex = s.LastIndexOf('E');
-
- if (Eindex > 0) { //если в строке есть Е+хх
- string E = s.TrimStart('E');
- s = s.Substring(0, n - E.Length);
- s += E;
- }
- else {
- s = s.Substring(0, n);
- }
- }
- return s;
- }
-
- public static string FormatString(this string s, int n, Positon pos, char filler = ' ')
- {
- if (s.Lengthn)
- {
- int Eindex = s.LastIndexOf('E');
-
- if (Eindex>0)
- { //если в строке есть Е+хх
- string E = s.TrimStart('E');
- s=s.Substring(0, n-E.Length);
- s+=E;
- }
- else
- {
- s=s.Substring(0, n);
- }
- }
- return s;
- }
-
- public enum Positon: byte { left,center,right}
-
- ///
- /// Slices the string form Start to End not including End
- ///
- ///
- ///
- ///
- ///
- public static string Slice(this string s, int Start = 0, int End = Int32.MaxValue)
- {
- if (Start < 0) throw new ArgumentOutOfRangeException(nameof(Start),Start,null);
- if (Start > End) throw new ArgumentOutOfRangeException(nameof(Start),Start,$"start ({Start}) is be bigger than end ({End})");
- if (End > s.Length) End = s.Length;
- return s.Substring(Start, End - Start);
- }
+ public static int GetHeaderHeight(this Form F)
+ {
+ Rectangle screenRectangle = F.RectangleToScreen(F.ClientRectangle);
+ return screenRectangle.Top - F.Top;
+ }
- ///
- /// Обрезает строку, начиная с первого появления StartsWith и заканчивая последним появлением EndsWith
- ///
- ///
- /// Строка, с которой будет происходить срезание
- /// Строка, до которой будет происходить срезание
- /// Возвращать строку, если начало или конец не найдены (иначе будет возвращен null)
- /// Начинать поиск Start с конца
- /// Начинать поиск Start с конца
- ///
- public static string Slice(this string s, string StartsWith, string EndsWith, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true)
- {
- var start = StartsWith == null? 0 : LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
-
- s = s.Slice(start);
+ public static int GetWindowPadding(this Form F, Orientation Side
+ ) => (int)((Side == Orientation.Horizontal? 6 : 5) * (F.DeviceDpi/96.0));
- var end = EndsWith==null? s.Length-1 : LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
+ public static Size MeasureText(Label l) => TextRenderer.MeasureText(l.Text,l.Font);
- return s.Slice(0,end);
- }
+ #region Image
- public static string SliceFromEnd(this string s, string StartsWith = null, string EndsWith = null, bool AlwaysReturnString = false, bool LastStart = false, bool LastEnd = true)
+ public static Image? Resize(this Image i, int NewDimensionValue, TypesFuncs.Dimension FixedDimension = TypesFuncs.Dimension.Height)
{
- var end = EndsWith==null? s.Length-1 : LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
-
- s = s.Slice(0, end);
-
- var start = StartsWith == null? 0 : LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(start);
- }
- public static string Slice(this string s, int Start, string EndsWith, bool AlwaysReturnString = false, bool LastEnd = true)
- {
- var end = LastEnd? s.LastIndexOf(EndsWith) : s.IndexOf(EndsWith);
- if (end < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(Start, end);
-
+ return i == null? null : new Bitmap(i, i.Size.Resize(NewDimensionValue, FixedDimension));
}
- public static string Slice(this string s, string StartsWith, int End = Int32.MaxValue, bool AlwaysReturnString = false, bool LastStart = false)
- {
- var start = LastStart? s.LastIndexOfEnd(StartsWith) : s.IndexOfEnd(StartsWith);
- if (start < 0) return AlwaysReturnString? s : null;
- return s.Slice(start, End);
+ #endregion
+ /*public static async Task ForegroundColorAnimation(this Control c, Color EndColor, int TimeMs)
+ {
+ double R = EndColor.R, G = EndColor.G, B = EndColor.B, A = EndColor.A;
+ double R_ = c.ForeColor.R, G_ = c.ForeColor.G, B_ = c.ForeColor.B, A_ = c.ForeColor.A;
+ int TimeNs = (TimeMs * 1000) / 256;
+ Timer timer = new Timer();
+ timer.Interval =
+ timer.Tick+=Timer_Tick(null);
+ }*/
+
+ ///
+ /// Class that makes some *Action* on all depedent controlls if one/all text of depedent controls is/not valid
+ ///
+ public class DependentControls
+ {
+ private readonly LogicType _logic;
+ private List _controls;
+ public bool isValid { get; private set; }
+ private delegate void ControlValidHandler(DependentControl sender, bool isValid);
+ public delegate void ValidHandler(bool isValid);
+ public event ValidHandler ValidChanged;
+ public Action DefaultValidFalseAction;
+ public Action DefaultValidTrueAction;
+ public Func DefaultValidCheck;
+ public enum LogicType
+ {
+ AND,
+ OR
}
///
- ///
+ /// All parametrs describes a default behavior for new added control
///
- ///
- /// Условия, которым должны удовлетворять символы начала строки (по функции на 1 символ)
- /// Условия, которым должны удовлетворять символы конца строки (по функции на 1 символ)
- /// Возвращать изначальную строку при неудачном поиске
- ///
- public static string Slice(this string s, Func[] StartConditions, Func[] EndConditions, bool AlwaysReturnString = false)
- {
- if (!StartConditions.Any()) throw new ArgumentNullException(nameof(StartConditions), "Условия начальной строки не заданы");
- if (!EndConditions.Any()) throw new ArgumentNullException(nameof(EndConditions), "Условия конечной строки не заданы");
-
- var start = s.IndexOfT(StartConditions,IndexOfEnd:true);
- if (start < 0) return AlwaysReturnString? s : null;
-
- var end =s.IndexOfT(EndConditions,LastOccuarance:true);
- if (end < 0) return AlwaysReturnString? s : null;
-
- return s.Slice(start, end);
- }
-
- public static string Slice(this string s, int Start, Func[] EndConditions, bool AlwaysReturnString = false)
+ /// Action that executes when control.text is NOT valid
+ /// Action that executes when control.text IS valid
+ /// Function that checks is control.text valid
+ public DependentControls(LogicType Logic, Action ValidFalseAction = null, Action ValidTrueAction = null, Func ValidCheck = null)
{
- if (!EndConditions.Any()) throw new ArgumentNullException(nameof(EndConditions), "Условия конечной строки не заданы");
-
- var end =s.IndexOfT(EndConditions,LastOccuarance:true);
- if (end < 0) return AlwaysReturnString? s.Slice(Start) : null;
+ _controls = new List();
+ _logic = Logic;
+ DefaultValidFalseAction = ValidFalseAction;
+ DefaultValidTrueAction = ValidTrueAction;
+ DefaultValidCheck = ValidCheck;
- return s.Slice(Start, end);
}
- public static string Slice(this string s, int Start, Regex EndRegex, bool AlwaysReturnString = false)
- {
- var end = EndRegex.Match(s).Index;
- if (end < 0) return AlwaysReturnString? s : null;
- return s.Slice(Start, end);
- }
-
- private static int IndexOfEnd(this string s, string s2)
+ public void Add(Control Control, Action ValidFalseAction= null, Action ValidTrueAction= null, Func ValidCheck = null)
{
- if (s == null)
- if (s2.Length == 0)
- return 0;
- int i = s.IndexOf(s2);
- return i == -1 ? -1 : i + s2.Length;
- }
+ ValidFalseAction ??= DefaultValidFalseAction ?? (_ => {});
+ ValidTrueAction ??= DefaultValidTrueAction;
+ ValidCheck ??= DefaultValidCheck;
+ var newControl = new DependentControl(_logic, Control, ValidFalseAction, ValidTrueAction, ValidCheck);
+ _controls.Add(newControl);
+ newControl.ValidChanged += ValidChangeReaction;
- ///
- /// Reports the position of a symbol next to last occurance of a string s2 (position after the end of s2)
- ///
- ///
- ///
- ///
- private static int LastIndexOfEnd(this string s, string s2)
- {
- if (s == null)
- if (s2.Length == 0) return 0;
- int i = s.LastIndexOf(s2);
- if (i == -1) return -1;
- else return i + s2.Length;
+ //newControl.CheckValidity();
}
- public enum DirectionEnum
- {
- Custom,
- Right,
- Left
- }
+ public void AddRange(List Controls, Action ValidFalseAction = null, Action ValidTrueAction = null, Func ValidCheck = null) =>
+ Controls.ForEach(Control => this.Add(Control, ValidFalseAction, ValidTrueAction, ValidCheck));
- public static int IndexOfT(this string s, Func[] Conditions, int Start = 0, int End = Int32.MaxValue, DirectionEnum Direction = DirectionEnum.Custom, bool IndexOfEnd = false, bool LastOccuarance = false)
+ private void ValidChangeReaction(object _sender, bool value)
{
- if (End == Int32.MaxValue) End = Direction == DirectionEnum.Left ? 0 : s.Length-1;
- if (Start < 0) Start = s.Length + Start;
- if (Start < 0) throw new ArgumentOutOfRangeException(nameof(Start),Start,$"incorrect negative Start ({Start - s.Length}). |Start| should be ≤ s.Length ({s.Length})");
- if (End < 0) End = s.Length + End;
- if (End < 0) throw new ArgumentOutOfRangeException(nameof(End),End,$"incorrect negative End ({End - s.Length}). |End| should be ≤ s.Length ({s.Length})");
-
- if (End == Start) return -2;
-
- if (Direction == DirectionEnum.Custom)
- Direction = End > Start ? DirectionEnum.Right : DirectionEnum.Left;
- else if ((Direction == DirectionEnum.Left && End > Start) || (Direction == DirectionEnum.Right && End < Start))
- Swap(ref Start, ref End);
-
- bool rightDirection = Direction == DirectionEnum.Right;
- int defaultCurMatchPos = rightDirection? 0 : s.Length-1;
- int curCondition = defaultCurMatchPos;
- int Result = -1;
-
- if (rightDirection)
- for (int i = Start; i < End; i++)
- {
- if (Conditions[curCondition](s[i]))
- {
- curCondition++;
- if (curCondition != Conditions.Length-1) continue;
- Result = i;
- curCondition = defaultCurMatchPos;
- if(!LastOccuarance) break;
- }
- else
- {
- curCondition = defaultCurMatchPos;
- }
- }
- else
- for (int i = Start; i >= End; i--)
+ var sender = _sender as DependentControl;
+ switch (_logic)
+ {
+ case LogicType.AND:
{
- if (Conditions[curCondition](s[i]))
+ if (value)
{
- curCondition--;
- if (curCondition != 0) continue;
- Result = i;
- curCondition = defaultCurMatchPos;
- if(!LastOccuarance) break;
- }
- else
- {
- curCondition = defaultCurMatchPos;
- }
- }
+ sender.ExecuteValidTrueAction();
+ bool temp = _controls.All(x => x.IsValid);
+ if(temp!= isValid) ValidChanged?.Invoke(temp);
+ isValid = temp;
- return IndexOfEnd ? Result : Result - Conditions.Length;
- }
-
- public static int IndexOfT(this string s, string s2, int Start = 0, int End = Int32.MaxValue, DirectionEnum Direction = DirectionEnum.Custom, bool IndexOfEnd = false, bool LastOccuarance = false)
- {
- if (End == Int32.MaxValue) End = Direction == DirectionEnum.Left ? 0 : s.Length-1;
- if (Start < 0) Start = s.Length + Start;
- if (Start < 0) new ArgumentOutOfRangeException(nameof(Start),Start,$"incorrect negative Start ({Start - s.Length}). |Start| should be ≤ s.Length ({s.Length})");
- if (End < 0) End = s.Length + End;
- if (End < 0) throw new ArgumentOutOfRangeException(nameof(End),End,$"incorrect negative End ({End - s.Length}). |End| should be ≤ s.Length ({s.Length})");
-
- if (End == Start) return -2;
- if (Direction == DirectionEnum.Custom)
- Direction = End > Start ? DirectionEnum.Right : DirectionEnum.Left;
- else if ((Direction == DirectionEnum.Left && End > Start) || (Direction == DirectionEnum.Right && End < Start))
- Swap(ref Start, ref End);
-
- bool rightDirection = Direction == DirectionEnum.Right;
- int defaultCurMatchPos = rightDirection? 0 : s.Length-1;
- int curMatchPos = defaultCurMatchPos;
- int Result = -1;
-
- if (rightDirection)
- for (int i = Start; i < End; i++)
- {
- if (s[i] == s2[curMatchPos])
- {
- curMatchPos++;
- if (curMatchPos != s2.Length) continue;
- Result = i;
- curMatchPos = defaultCurMatchPos;
- if(!LastOccuarance) break;
}
else
{
- curMatchPos = defaultCurMatchPos;
+ sender.ExecuteValidFalseAction();
+ if(isValid) ValidChanged?.Invoke(false);
+ isValid = false;
+
}
- }
- else
- for (int i = Start; i >= End; i--)
+ } break;
+
+ case LogicType.OR:
{
- if (s[i] == s2[curMatchPos])
+ if (value)
{
- curMatchPos--;
- if (curMatchPos != 0) continue;
- Result = i;
- curMatchPos = defaultCurMatchPos;
- if(!LastOccuarance) break;
+ if (!isValid) ValidChanged?.Invoke(true);
+ isValid = true;
+ foreach (var c in _controls)
+ c.ExecuteValidTrueAction();
}
- else
+ else
{
- curMatchPos = defaultCurMatchPos;
+ bool temp = false;
+ foreach (var c in _controls)
+ {
+ if (c.IsValid) {temp = true; break;}
+ }
+ if(!temp) foreach (var c in _controls)
+ c.ExecuteValidFalseAction();
+ if(temp!=isValid) ValidChanged?.Invoke(temp);
+ isValid = temp;
}
- }
-
- return IndexOfEnd? Result : Result - s2.Length;
- }
-
-
- public static string Multiply(this string s, int count)
- {
- StringBuilder sb = new StringBuilder(s.Length*count);
- for (int i = 0; i < count; i++)
- {
- sb.Append(s);
- }
-
- return sb.ToString();
- }
-
- public static string Multiply(this char s, int count)
- {
- StringBuilder sb = new StringBuilder(count);
- for (int i = 0; i < count; i++)
- {
- sb.Append(s);
+ } break;
}
-
- return sb.ToString();
- }
-
-
- ///
- /// s[..Start] + NewString + s[End..]
- ///
- /// original string
- /// String from 0 to Start will be added before NewString
- /// String from End to s.Length-1 will be added after NewString. If null, End = NewString.Length, or null if there's no NewString
- /// String that will be between Start and End. If null, you'll just cut the text between Start and End
- /// if false, its returns original string instead of exception
- ///
- public static string Replace(this string s, int Start, int? End = null, string NewString = null, bool Exception = true)
- {
- if (Start < 0) Start = s.Length - Start;
- if (Start < 0 || Start > s.Length)
- if (Exception) throw new ArgumentOutOfRangeException($"There's no position {Start} in string s[{s.Length}]");
- else return s;
-
- if (End != null)
- {
- if (End < 0) End = s.Length - End;
- if (End < 0 || End > s.Length)
- if (Exception) throw new ArgumentOutOfRangeException($"There's no position {End} in string s[{s.Length}]");
- else if (End > s.Length) End = s.Length - 1;
- else return s;
- }
- else End = Start + NewString?.Length?? 0;
-
- if (Start == End && string.IsNullOrEmpty(NewString)) return s;
- if (End < s.Length) return s[..Start] + NewString + s[(int)End..];
- else return s[..Start] + NewString;
}
- public static string ReplaceFromLast(this string s, string OldString, string NewString, bool Exception = true)
+ class DependentControl
{
- if (OldString is null)
- {
- if (Exception) throw new ArgumentNullException(nameof(OldString));
- else return s;
- }
- var start = s.LastIndexOf(OldString, StringComparison.Ordinal);
- return s.Replace(start, start+OldString.Length, NewString, Exception);
- }
+ private LogicType _logic;
+ internal Control Control;
+ private readonly Control InitialControl;
- ///
- /// Adds unadded part of to in the end of . "stringTest".Add("Testing") //"stringTesting" will be unchanged if is already added to "Test".Add("st") //"Test". Replacement occuts only in end "Tests".Add("Testing") //"TestsTesting"
- ///
- /// Initial string
- /// String that should be in the end of
- ///
- public static string Add(this string s, string addiction)
- {
- int offset = 0;
+ public bool IsValid { get; private set; }
+ private event ControlValidHandler _validChanged;
- //:Searches for *addiction* in the end of the *s*
- for (; offset < addiction.Length; offset++)
+ public event ControlValidHandler ValidChanged
{
- if (s[^1] != addiction[offset]) continue;
- int aPosition = offset;
- for (int sPosition = s.Length-1; sPosition >0;)
+ add
{
- if (s[sPosition--] != addiction[aPosition--]) break;
- if (aPosition < 0)
- {
- return s + addiction[(offset+1)..];
- }
+ _validChanged += value;
+ CheckValidity();
+ _validChanged?.Invoke(this, IsValid);
}
+ remove => _validChanged -= value;
}
- return s+addiction;
- }
-
-
- #endregion
-
- #region Double
-
- public static bool isEven(this int number) => number % 2 == 0;
-
- #endregion
-
- #region Array
-
- public static int IndexOf(this T[] array, T value) => Array.IndexOf(array, value);
-
- public static T[][] Split(this T[] array, int arraysCount)
- {
- var arraysSize = DivRem(array.Length,arraysCount,out int lastArraySize);
- if (lastArraySize == 0) lastArraySize = arraysSize;
+ private Func _validCheck;
+ private Action _validFalseAction;
+ private Action _validTrueAction;
- T[][] resultArrays = new T[arraysCount][];
- int k = 0;
- for (int i = 0; i < arraysCount-1; i++)
+ public DependentControl(LogicType logic, Control Control, Action ValidFalseAction, Action ValidTrueAction = null, Func ValidCheck = null)
{
- resultArrays[i] = new T[arraysSize];
- for (int j = 0; j < arraysSize; j++)
- {
- resultArrays[i][j] = array[k++];
- }
+ _logic = logic;
+ this.Control = Control;
+ InitialControl = Control.Clone();
+ _validCheck = ValidCheck ?? (x => x != "");
+ IsValid = _validCheck(Control.Text);
+ _validFalseAction = ValidFalseAction;
+ _validTrueAction = ValidTrueAction?? ((_control) => InitialControl.CopyPropertiesTo(_control));
+
+ Control.TextChanged +=Control_TextChanged;
}
- resultArrays[^1] = new T[lastArraySize];
- for (int j = 0; j < lastArraySize; j++)
+ private void Control_TextChanged(object sender, EventArgs e) //TODO: можно сделать с таймером для оптимизации
{
- resultArrays[^1][j] = array[k++];
+ CheckValidity();
}
- return resultArrays;
- }
- public static int GetMaxIndex(this double[] array)
- {
- int MaxIndex = 0;
- double MaxValue = array[0];
+ internal void ExecuteValidTrueAction() => _validTrueAction(Control);
+ internal void ExecuteValidFalseAction() => _validFalseAction(Control);
- for (int i = 1; i < array.Length; i++)
+ public bool CheckValidity()
{
- if (array[i] > MaxValue)
+ bool old = IsValid;
+ IsValid = _validCheck(Control.Text);
+ if (old != IsValid)
{
- MaxValue = array[i];
- MaxIndex = i;
+ _validChanged?.Invoke(this, IsValid);
}
- }
-
- return MaxIndex;
- }
- public static T[] Concat(T[] Array1, T[] Array2)
- {
- T[] res = new T[Array1.Length + Array2.Length];
- for (int i = 0; i < Array1.Length; i++)
- {
- res[i] = Array1[i];
- }
- for (int i = 0; i < Array2.Length; i++)
- {
- res[i + Array1.Length] = Array2[i];
+ return (bool)IsValid;
}
-
- return res;
}
+ }
- public static T[] ReduceDimension(this T[][] Arrays)
- {
- int arraySize = 0;
- for (int i = 0; i < Arrays.Length; i++)
- {
- arraySize += Arrays[i].Length;
- }
-
- T[] res = new T[arraySize];
- int k = 0;
- foreach (var array in Arrays)
- {
- foreach (var item in array)
- {
- res[k++] = item;
- }
- }
+ ///
+ /// Just Picture and text to the right to the picture. Not a standalone control because I don't really want to mess up with learning to how to render it, phew
+ ///
+ internal class PictureText : Control
+ {
+ private readonly PictureBox Picture;
+ private readonly Label Label;
- return res;
- }
-
- public static string ToStringLine(this T[] Array, string Separator = " ")
+ public PictureText(Point Location, Bitmap Image, int ImageHeight, string Text, int Spacing, VerticalAlignment TextAlignment = VerticalAlignment.Center)
{
- string result = "";
- foreach (var el in Array)
- {
- result += el + Separator;
- }
+ this.Location = Location;
- return result[..^Separator.Length];
- }
+ Picture = new PictureBox();
+ Picture.Location = Location;
+ Picture.BackgroundImage = Image;
+ Picture.Size = Image.Size.Resize(ImageHeight);
+ Picture.BackgroundImageLayout = ImageLayout.Zoom;
- public static string ToStringLine(this List Array, string Separator = " ")
- {
- string result = "";
- foreach (var el in Array)
- {
- result += el + Separator;
- }
+ Label = new Label();
+ Label.Text = Text;
+ Label.Padding = Padding.Empty;
+ Label.Margin = Padding.Empty;
+ Label.Size = MeasureText(Label)+ new Size(4,0);
+ Label.Location = new Point(
+ Location.X + Spacing + Picture.Width,
+ TextAlignment switch
+ {
+ VerticalAlignment.Top => Location.Y,
+ VerticalAlignment.Center => Location.Y + ImageHeight/2 - Label.Size.Height/2,
+ VerticalAlignment.Bottom => Location.Y + ImageHeight - Label.Size.Height,
+ _ => throw new ArgumentOutOfRangeException(nameof(TextAlignment), TextAlignment, null)
+ });
- return result[..^Separator.Length];
+ Size = new(Picture.Width + Spacing + Label.Width, Math.Max(Picture.Height, Label.Height));
}
- public static T[] FillAndGet(this T[] source, T value)
+ public void AddTo(Control control)
{
- for (int i = 0; i < source.Length; i++)
- source[i] = value;
-
- return source;
+ control.Controls.AddRange(new Control[]{Picture, Label});
}
+ }
- public static T[] AddRangeAndGet(this T[] array, T[] summand)
- {
- var newArray = new T[array.Length + summand.Length];
- for (int i = 0; i < array.Length; i++)
- {
- newArray[i] = array[i];
- }
- for (int i = 0; i < summand.Length; i++)
- {
- newArray[i + array.Length] = summand[i];
- }
+ public class PictureTextCollection
+ {
+ // ReSharper disable once FieldCanBeMadeReadOnly.Local
+ private List _items;
- return newArray;
- }
+ //public List Items => _items;
+ public Point Location { get; }
+ public int Count => _items.Count;
+ public int ImageHeight;
+ public int ImageToTextDistance;
+ public int ImageToImageDistance;
+ public VerticalAlignment TextAlignment;
+ public Size Size = Size.Empty;
+ public int Width => Size.Width;
+ public int Height => Size.Height;
+ public Panel ParentPanel;
- public static List AddRangeAndGet(this List list, List summand)
+ public PictureTextCollection(Point Location, int ImageHeight, int ImageToTextDistance, int ImageToImageDistance, Panel ParentPanel, VerticalAlignment TextAlignment = VerticalAlignment.Center)
{
- list.AddRange(summand);
- return list;
- }
+ this.ImageHeight = ImageHeight;
+ this.ImageToTextDistance = ImageToTextDistance;
+ this.Location = Location;
+ this.ImageToImageDistance = ImageToImageDistance;
+ this.ParentPanel = ParentPanel;
+ this.TextAlignment = TextAlignment;
- public static string Remove(this string S, string RemovableString, StringComparison ComparisonType = StringComparison.Ordinal)
- {
- if (RemovableString is null or "") return S;
- int startPos = S.IndexOf(RemovableString, ComparisonType);
- return startPos == -1 ? S : S.Remove(startPos, RemovableString.Length);
+ _items = new List();
}
- public static string RemoveAll(this string S, string RemovableString, StringComparison ComparisonType = StringComparison.Ordinal)
+ public void Add(Bitmap Image, string Text)
{
- if (RemovableString is null or "") return S;
-
- while (true)
- {
- int startPos = S.IndexOf(RemovableString,ComparisonType);
- if (startPos == -1) return S;
-
- S = S.Remove(startPos, RemovableString.Length);
- }
+ Point newLocation = Count == 0 ? Location : new Point(Location.X, _items.Last().Location.Y + _items.Last().Size.Height + ImageToImageDistance);
+ var item = new PictureText(newLocation, Image, ImageHeight, Text, ImageToTextDistance);
+ _items.Add(item);
+ item.AddTo(ParentPanel);
+ Size = new Size(
+ Math.Max(Width, item.Width),
+ Height == 0? (item.Height) : (Height + ImageToImageDistance + item.Height));
}
- #endregion
-
- #region Size
-
- // returns the highest dimension
- public static int Max(this Size s) => Math.Max(s.Height, s.Width);
- // returns the lowest dimension
- public static int Min(this Size s) => Math.Min(s.Height, s.Width);
-
- ///
- /// Returns the new Size with same aspect ratio
- ///
- /// original size
- ///
- /// Dimension you just wrote
- ///
- public static Size Resize(this Size s, int NewDimensionValue, Dimension FixedDimension = Dimension.Height)
- {
- if ((FixedDimension is Dimension.Height && s.Height == 0) || (FixedDimension is Dimension.Width && s.Width == 0)) throw new ArgumentOutOfRangeException(nameof(s), $"original {FixedDimension} can't be 0");
-
- return FixedDimension switch
- {
- Dimension.Height => new Size((s.Width * NewDimensionValue) / s.Height, NewDimensionValue),
- Dimension.Width => new Size(NewDimensionValue, (s.Height * NewDimensionValue) / s.Width),
- _ => throw new ArgumentOutOfRangeException(nameof(FixedDimension), FixedDimension, null)
- };
- }
-
- public enum Dimension
+ public void AddRange(Bitmap[] Images, string[] Texts)
+ {
+ if (Images.Length != Texts.Length) throw new ArgumentException("Arrays should have same length");
+ for (int i = 0; i < Images.Length; i++)
{
- Height,
- Width
+ Add(Images[i], Texts[i]);
}
- #endregion
-
- #region Image
-
-
- public static Image Resize(this Image i, int NewDimensionValue, Dimension FixedDimension = Dimension.Height)
- {
- return i == null? null : new Bitmap(i, i.Size.Resize(NewDimensionValue, FixedDimension));
}
- #endregion
-
- #region Color
-
- static Color Change(this Color c, byte? A = null, byte? R = null, byte? G = null, byte? B = null) => Color.FromArgb(A?? c.A, R??c.R, G??c.G, B??c.B);
-
- #endregion
-
- #region Universal Type
-
- public static void Swap(ref T a, ref T b)
- {
- T c = a;
- a = b;
- b = c;
- }
-
- public static bool IsDefault(this T value) where T : struct
- {
- bool isDefault = value.Equals(default(T));
-
- return isDefault;
- }
-
- public static IEnumerable ToDefault_IfNot(this IEnumerable s, Func predicate) => s?.Any(predicate) is true ? s : null;
- public static T ToDefault_IfNot(this T s, Func predicate) where T : struct => predicate(s)? s : default;
-
- #endregion
-
- #endregion
+ }
+ }
+ public static class ErrorTaskDialog
+ {
+ public static string Language = "English";
+ private static bool DictionaryInitialized = false;
+
+ private static class ETDLocalizaton
+ {
+ internal static string OpenMicrosoftDocs;
+ internal static string Close;
+ internal static string Copy_to_Clipboard;
+ internal static string Open_Inner_Exception;
+ internal static string Title;
+ }
+
+ public static void InitializeDictionary(string OpenMicrosoftDocs = "Open Microsoft documentation", string Copy_to_Clipboard = "Copy to Clipboard", string Open_Inner_Exception = "Open inner exception", string Close = "Close", string Title = "Error")
+ {
+ DictionaryInitialized = true;
+
+ ETDLocalizaton.OpenMicrosoftDocs = OpenMicrosoftDocs;
+ ETDLocalizaton.Close = Close;
+ ETDLocalizaton.Copy_to_Clipboard = Copy_to_Clipboard;
+ ETDLocalizaton.Open_Inner_Exception = Open_Inner_Exception;
+ ETDLocalizaton.Title = Title;
+ }
+ public static void ShowMessageBox(this Exception? Error, string? Title = null)
+ {
+ if(Error == null) return;
+ if(!DictionaryInitialized) InitializeDictionary();
+
+
+ Ookii.Dialogs.WinForms.TaskDialog taskDialog = new();
+ taskDialog.WindowTitle = Title ?? ETDLocalizaton.Title;
+ taskDialog.Content = Error.Message;
+ //if(Error.Data.Count!=0) taskDialog.CollapsedControlText = Error.Data.ToDictionary().ToStringT();
+ if(Error.HelpLink!=null) taskDialog.Footer = $"{ETDLocalizaton.OpenMicrosoftDocs}";
+ TaskDialogButton closeBtn = new(ETDLocalizaton.Close),
+ copyBtn = new(ETDLocalizaton.Copy_to_Clipboard),
+ innerExceptionBtn = new(ETDLocalizaton.Open_Inner_Exception);
+ innerExceptionBtn.Enabled = Error.InnerException != null;
+ taskDialog.Buttons.Add(closeBtn);
+ taskDialog.Buttons.Add(copyBtn);
+ taskDialog.Buttons.Add(innerExceptionBtn);
+
+ var button = taskDialog.ShowDialog();
+ if(button == closeBtn) taskDialog.Dispose();
+ if(button == copyBtn) {Thread thread = new(() => Clipboard.SetText(Error.Message));
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+ Error.ShowMessageBox();
+ }
+ if(button == innerExceptionBtn)
+ Error.InnerException.ShowMessageBox();
+ }
}
}
diff --git a/Properties/Localization/LocalizationStrings.Designer.cs b/Properties/Localization/LocalizationStrings.Designer.cs
index aa35292..49345f5 100644
--- a/Properties/Localization/LocalizationStrings.Designer.cs
+++ b/Properties/Localization/LocalizationStrings.Designer.cs
@@ -19,7 +19,7 @@ namespace SteamVR_OculusDash_Switcher.Properties.Localization {
// с помощью такого средства, как ResGen или Visual Studio.
// Чтобы добавить или удалить член, измените файл .ResX и снова запустите ResGen
// с параметром /str или перестройте свой проект VS.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class LocalizationStrings {
@@ -106,7 +106,7 @@ internal static string ControlsTipsForm__TitleText {
}
///
- /// Ищет локализованную строку, похожую на Break/Restore SteamVR.
+ /// Ищет локализованную строку, похожую на Switch SteamVR ↔ Oculus.
///
internal static string ControlsTipsForm_tip__LMB {
get {
@@ -304,6 +304,15 @@ internal static string MessageBox_Title__Error {
}
}
+ ///
+ /// Ищет локализованную строку, похожую на Select Oculus folder path.
+ ///
+ internal static string OculusDash_OculusNotFound__Select_Oculus_folder_path {
+ get {
+ return ResourceManager.GetString("OculusDash_OculusNotFound__Select_Oculus_folder_path", resourceCulture);
+ }
+ }
+
///
/// Ищет локализованную строку, похожую на Newest Oculus Killer was downloaded successfully.
///
@@ -331,6 +340,24 @@ internal static string OculusKiller_StatusDiscription_Updated {
}
}
+ ///
+ /// Ищет локализованную строку, похожую на Interface.
+ ///
+ internal static string SettingsForm__Interface {
+ get {
+ return ResourceManager.GetString("SettingsForm__Interface", resourceCulture);
+ }
+ }
+
+ ///
+ /// Ищет локализованную строку, похожую на General functions.
+ ///
+ internal static string SettingsForm__Main_functions {
+ get {
+ return ResourceManager.GetString("SettingsForm__Main_functions", resourceCulture);
+ }
+ }
+
///
/// Ищет локализованную строку, похожую на Saved!.
///
diff --git a/Properties/Localization/LocalizationStrings.resx b/Properties/Localization/LocalizationStrings.resx
index f2336ba..2648dda 100644
--- a/Properties/Localization/LocalizationStrings.resx
+++ b/Properties/Localization/LocalizationStrings.resx
@@ -196,7 +196,7 @@
Open context menu
- Break/Restore SteamVR
+ Switch SteamVR ↔ Oculus
Kill SteamVR
@@ -277,4 +277,13 @@
Checking updates...
+
+ Select Oculus folder path
+
+
+ General functions
+
+
+ Interface
+
\ No newline at end of file
diff --git a/Properties/Localization/LocalizationStrings.ru.resx b/Properties/Localization/LocalizationStrings.ru.resx
index d69bac8..9642b6e 100644
--- a/Properties/Localization/LocalizationStrings.ru.resx
+++ b/Properties/Localization/LocalizationStrings.ru.resx
@@ -196,7 +196,7 @@
Открыть контекстное меню
- Сломать/Восстановить SteamVR
+ Переключить SteamVR ↔ Oculus
Убить SteamVR
@@ -271,4 +271,13 @@
Проверка обновлений...
+
+ Выберите путь папки Oculus
+
+
+ Основные функции
+
+
+ Интерфейс
+
\ No newline at end of file
diff --git a/Readme images/Settings_1.jpg b/Readme images/Settings_1.jpg
new file mode 100644
index 0000000..23b27eb
Binary files /dev/null and b/Readme images/Settings_1.jpg differ
diff --git a/Readme images/SteamVR modes_1.jpg b/Readme images/SteamVR modes_1.jpg
new file mode 100644
index 0000000..eb7c98c
Binary files /dev/null and b/Readme images/SteamVR modes_1.jpg differ
diff --git a/Readme images/Tray menu_1.jpg b/Readme images/Tray menu_1.jpg
new file mode 100644
index 0000000..617a628
Binary files /dev/null and b/Readme images/Tray menu_1.jpg differ
diff --git a/SteamVR-OculusDash Switcher.csproj b/SteamVR-OculusDash Switcher.csproj
index c7f538a..8dab0da 100644
--- a/SteamVR-OculusDash Switcher.csproj
+++ b/SteamVR-OculusDash Switcher.csproj
@@ -15,6 +15,7 @@
https://github.com/TuTAH1/SteamVR-OculusDash-Switcher
en-US
true
+ 10
@@ -39,7 +40,9 @@
+
+
diff --git a/Test/Form1.Designer.cs b/Test/Form1.Designer.cs
new file mode 100644
index 0000000..089e680
--- /dev/null
+++ b/Test/Form1.Designer.cs
@@ -0,0 +1,60 @@
+
+namespace SteamVR_OculusDash_Switcher.Forms
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null)) {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(12, 9);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(59, 25);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "label1";
+ //
+ // Form1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(800, 450);
+ this.Controls.Add(this.label1);
+ this.Name = "Form1";
+ this.Text = "Form1";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ }
+}
\ No newline at end of file
diff --git a/Test/Form1.cs b/Test/Form1.cs
new file mode 100644
index 0000000..d1dcea7
--- /dev/null
+++ b/Test/Form1.cs
@@ -0,0 +1,22 @@
+using System.Diagnostics;
+using System.Windows.Forms;
+
+namespace SteamVR_OculusDash_Switcher.Forms
+{
+ public partial class Form1 : Form
+ {
+ public Form1()
+ {
+ InitializeComponent();
+ Stopwatch test = Stopwatch.StartNew();
+ var lab = new Label();
+ this.Controls.Add(lab);
+ //label1.CopyPropertiesTo(lab);
+ lab.Text = "Test";
+ lab.Top = 20;
+ //lab.Top += lab.Height + lab.Padding.Top;
+ test.Stop();
+ MessageBox.Show(test.ElapsedMilliseconds.ToString());
+ }
+ }
+}
diff --git a/Test/Form1.resx b/Test/Form1.resx
new file mode 100644
index 0000000..f298a7b
--- /dev/null
+++ b/Test/Form1.resx
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file