This commit is contained in:
Stephan Maier
2024-08-27 08:10:27 +02:00
parent eb5c2fa502
commit 647f938eee
617 changed files with 73086 additions and 7137 deletions

View File

@@ -0,0 +1,115 @@
// <copyright file="App.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu
{
using System;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using FSI.BT.Tools.SystemTrayMenu.Business;
using FSI.BT.Tools.SystemTrayMenu.Helper.Updater;
using FSI.BT.Tools.SystemTrayMenu.UserInterface;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using FSI.BT.Tools.Global.Utilities;
/// <summary>
/// App contains the notifyicon, the taskbarform and the menus.
/// </summary>
internal class App : IDisposable
{
private readonly AppNotifyIcon menuNotifyIcon = new();
private readonly Menus menus = new();
private readonly TaskbarForm taskbarForm = null;
public App()
{
AppRestart.BeforeRestarting += Dispose;
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
menus.LoadStarted += menuNotifyIcon.LoadingStart;
menus.LoadStopped += menuNotifyIcon.LoadingStop;
menuNotifyIcon.Click += MenuNotifyIcon_Click;
menuNotifyIcon.OpenLog += Log.OpenLogFile;
menus.MainPreload();
if (Global.Vars.SystemTrayMenuSettings.ShowInTaskbar)
{
taskbarForm = new TaskbarForm();
taskbarForm.FormClosed += TaskbarForm_FormClosed;
taskbarForm.Deactivate += SetStateNormal;
taskbarForm.Resize += SetStateNormal;
taskbarForm.Activated += TasbkarItemActivated;
}
BT.Tools.Global.DllImports.NativeMethods.User32ShowInactiveTopmost(taskbarForm);
//if (Global.Vars.SystemTrayMenuSettings.CheckForUpdates)
//{
// new Thread((obj) => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(
// showWhenUpToDate: false))
// .Start();
//}
}
public void Dispose()
{
if (taskbarForm?.InvokeRequired == true)
{
taskbarForm.Invoke(Dispose);
}
else
{
AppRestart.BeforeRestarting -= Dispose;
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
menus.LoadStarted -= menuNotifyIcon.LoadingStart;
menus.LoadStopped -= menuNotifyIcon.LoadingStop;
menus.Dispose();
menuNotifyIcon.Click -= MenuNotifyIcon_Click;
menuNotifyIcon.OpenLog -= Log.OpenLogFile;
menuNotifyIcon.Dispose();
if (taskbarForm != null)
{
taskbarForm.FormClosed -= TaskbarForm_FormClosed;
taskbarForm.Deactivate -= SetStateNormal;
taskbarForm.Resize -= SetStateNormal;
taskbarForm.Activated -= TasbkarItemActivated;
taskbarForm.Dispose();
}
}
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
menus.ReAdjustSizeAndLocation();
}
private void MenuNotifyIcon_Click()
{
menus.SwitchOpenClose(true);
}
private void TaskbarForm_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
/// <summary>
/// This ensures that next click on taskbaritem works as activate event/click event.
/// </summary>
private void SetStateNormal(object sender, EventArgs e)
{
if (Form.ActiveForm == taskbarForm)
{
taskbarForm.WindowState = FormWindowState.Normal;
}
}
private void TasbkarItemActivated(object sender, EventArgs e)
{
SetStateNormal(sender, e);
taskbarForm.Activate();
taskbarForm.Focus();
menus.SwitchOpenCloseByTaskbarItem();
}
}
}

View File

@@ -0,0 +1,592 @@
// <copyright file="KeyboardInput.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Handler
{
using System;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
using FSI.BT.Tools.SystemTrayMenu.Helper;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class KeyboardInput : IDisposable
{
private readonly Menu[] menus;
private readonly KeyboardHook hook = new();
private int iRowKey = -1;
private int iMenuKey;
public KeyboardInput(Menu[] menus)
{
this.menus = menus;
}
public event Action HotKeyPressed;
public event Action ClosePressed;
public event Action<DataGridView, int> RowSelected;
public event Action<DataGridView, int> RowDeselected;
public event Action<DataGridView, int> EnterPressed;
public event Action Cleared;
public bool InUse { get; set; }
public void Dispose()
{
hook.KeyPressed -= Hook_KeyPressed;
hook.Dispose();
}
public void RegisterHotKey()
{
if (!string.IsNullOrEmpty(Global.Vars.SystemTrayMenuSettings.HotKey))
{
try
{
hook.RegisterHotKey();
hook.KeyPressed += Hook_KeyPressed;
}
catch (InvalidOperationException ex)
{
Log.Warn($"key:'{Global.Vars.SystemTrayMenuSettings.HotKey}'", ex);
Global.Vars.SystemTrayMenuSettings.HotKey = string.Empty;
//Global.Vars.SystemTrayMenuSettings.Save();
}
}
}
public void ResetSelectedByKey()
{
iRowKey = -1;
iMenuKey = 0;
}
public void CmdKeyProcessed(object sender, Keys keys)
{
sender ??= menus[iMenuKey];
switch (keys)
{
case Keys.Enter:
SelectByKey(keys);
menus[iMenuKey]?.FocusTextBox();
break;
case Keys.Left:
SelectByKey(keys);
break;
case Keys.Right:
SelectByKey(keys);
break;
case Keys.Home:
case Keys.End:
case Keys.Up:
case Keys.Down:
case Keys.Escape:
case Keys.Alt | Keys.F4:
SelectByKey(keys);
break;
case Keys.Control | Keys.F:
menus[iMenuKey]?.FocusTextBox();
break;
case Keys.Tab:
{
Menu currentMenu = (Menu)sender;
int indexOfTheCurrentMenu = GetMenuIndex(currentMenu);
int indexMax = menus.Where(m => m != null).Count() - 1;
int indexNew = 0;
if (indexOfTheCurrentMenu > 0)
{
indexNew = indexOfTheCurrentMenu - 1;
}
else
{
indexNew = indexMax;
}
menus[indexNew]?.FocusTextBox();
}
break;
case Keys.Tab | Keys.Shift:
{
Menu currentMenu = (Menu)sender;
int indexOfTheCurrentMenu = GetMenuIndex(currentMenu);
int indexMax = menus.Where(m => m != null).Count() - 1;
int indexNew = 0;
if (indexOfTheCurrentMenu < indexMax)
{
indexNew = indexOfTheCurrentMenu + 1;
}
else
{
indexNew = 0;
}
menus[indexNew]?.FocusTextBox();
}
break;
case Keys.Apps:
{
DataGridView dgv = menus[iMenuKey]?.GetDataGridView();
if (iRowKey > -1 &&
dgv.Rows.Count > iRowKey)
{
Point point = dgv.GetCellDisplayRectangle(2, iRowKey, false).Location;
RowData trigger = (RowData)dgv.Rows[iRowKey].Cells[2].Value;
MouseEventArgs mouseEventArgs = new(MouseButtons.Right, 1, point.X, point.Y, 0);
trigger.MouseDown(dgv, mouseEventArgs);
}
}
break;
default:
break;
}
int GetMenuIndex(in Menu currentMenu)
{
int index = 0;
foreach (Menu menuFindIndex in menus.Where(m => m != null))
{
if (currentMenu == menuFindIndex)
{
break;
}
index++;
}
return index;
}
}
public void SearchTextChanging()
{
ClearIsSelectedByKey();
}
public void SearchTextChanged(Menu menu, bool isSearchStringEmpty)
{
DataGridView dgv = menu.GetDataGridView();
if (isSearchStringEmpty)
{
ClearIsSelectedByKey();
}
else if (dgv.Rows.Count > 0)
{
Select(dgv, 0, true);
}
}
public void ClearIsSelectedByKey()
{
ClearIsSelectedByKey(iMenuKey, iRowKey);
}
public void Select(DataGridView dgv, int i, bool refreshview)
{
int newiMenuKey = ((Menu)dgv.TopLevelControl).Level;
if (i != iRowKey || newiMenuKey != iMenuKey)
{
ClearIsSelectedByKey();
}
iRowKey = i;
iMenuKey = newiMenuKey;
if (dgv.Rows.Count > i)
{
DataGridViewRow row = dgv.Rows[i];
RowData rowData = (RowData)row.Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = true;
}
if (refreshview)
{
row.Selected = false;
row.Selected = true;
}
}
}
private void Hook_KeyPressed(object sender, KeyPressedEventArgs e)
{
HotKeyPressed?.Invoke();
}
private bool IsAnyMenuSelectedByKey(
ref DataGridView dgv,
ref Menu menuFromSelected,
ref string textselected)
{
Menu menu = menus[iMenuKey];
bool isStillSelected = false;
if (menu != null &&
iRowKey > -1)
{
dgv = menu.GetDataGridView();
if (dgv.Rows.Count > iRowKey)
{
RowData rowData = (RowData)dgv.
Rows[iRowKey].Cells[2].Value;
if (rowData.IsSelected)
{
isStillSelected = true;
menuFromSelected = rowData.SubMenu;
textselected = dgv.Rows[iRowKey].
Cells[1].Value.ToString();
}
}
}
return isStillSelected;
}
private void SelectByKey(Keys keys, string keyInput = "", bool keepSelection = false)
{
int iRowBefore = iRowKey;
int iMenuBefore = iMenuKey;
Menu menu = menus[iMenuKey];
DataGridView dgv = null;
DataGridView dgvBefore = null;
Menu menuFromSelected = null;
string textselected = string.Empty;
bool isStillSelected = IsAnyMenuSelectedByKey(ref dgv, ref menuFromSelected, ref textselected);
if (isStillSelected)
{
if (keepSelection)
{
// If current selection is still valid for this search then skip selecting different item
if (textselected.StartsWith(keyInput, true, CultureInfo.InvariantCulture))
{
return;
}
}
dgvBefore = dgv;
}
else
{
ResetSelectedByKey();
menu = menus[iMenuKey];
dgv = menu.GetDataGridView();
}
bool toClear = false;
switch (keys)
{
case Keys.Enter:
if (iRowKey > -1 && dgv.Rows.Count > iRowKey)
{
RowData trigger = (RowData)dgv.Rows[iRowKey].Cells[2].Value;
if (trigger.IsMenuOpen || !trigger.ContainsMenu)
{
trigger.MouseClick(null, out bool toCloseByMouseClick);
trigger.DoubleClick(
new MouseEventArgs(MouseButtons.Left, 0, 0, 0, 0),
out bool toCloseByDoubleClick);
if (toCloseByMouseClick || toCloseByDoubleClick)
{
ClosePressed?.Invoke();
}
if (iRowKey > -1 && dgv.Rows.Count > iRowKey)
{
// Raise Dgv_RowPostPaint to show ProcessStarted
dgv.InvalidateRow(iRowKey);
}
}
else
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
EnterPressed.Invoke(dgv, iRowKey);
}
}
break;
case Keys.Up:
if (SelectMatchedReverse(dgv, iRowKey) ||
SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
break;
case Keys.Down:
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
break;
case Keys.Home:
if (SelectMatched(dgv, 0))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
break;
case Keys.End:
if (SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
break;
case Keys.Left:
bool nextMenuLocationIsLeft = menus[iMenuKey + 1] != null && menus[iMenuKey + 1].Location.X < menus[iMenuKey].Location.X;
bool previousMenuLocationIsRight = iMenuKey > 0 && menus[iMenuKey]?.Location.X < menus[iMenuKey - 1]?.Location.X;
if (nextMenuLocationIsLeft || previousMenuLocationIsRight)
{
SelectNextMenu(iRowBefore, ref dgv, dgvBefore, menuFromSelected, isStillSelected, ref toClear);
}
else if (iMenuKey > 0)
{
SelectPreviousMenu(iRowBefore, ref menu, ref dgv, dgvBefore, ref toClear);
}
break;
case Keys.Right:
bool nextMenuLocationIsRight = menus[iMenuKey + 1]?.Location.X > menus[iMenuKey]?.Location.X;
bool previousMenuLocationIsLeft = iMenuKey > 0 && menus[iMenuKey]?.Location.X > menus[iMenuKey - 1]?.Location.X;
if (nextMenuLocationIsRight || previousMenuLocationIsLeft)
{
SelectNextMenu(iRowBefore, ref dgv, dgvBefore, menuFromSelected, isStillSelected, ref toClear);
}
else if (iMenuKey > 0)
{
SelectPreviousMenu(iRowBefore, ref menu, ref dgv, dgvBefore, ref toClear);
}
break;
case Keys.Escape:
case Keys.Alt | Keys.F4:
RowDeselected(dgvBefore, iRowBefore);
iMenuKey = 0;
iRowKey = -1;
toClear = true;
ClosePressed?.Invoke();
break;
default:
if (!string.IsNullOrEmpty(keyInput))
{
if (SelectMatched(dgv, iRowKey, keyInput) ||
SelectMatched(dgv, 0, keyInput))
{
RowDeselected(null, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
else if (isStillSelected)
{
iRowKey = iRowBefore - 1;
if (SelectMatched(dgv, iRowKey, keyInput) ||
SelectMatched(dgv, 0, keyInput))
{
RowDeselected(null, iRowBefore);
SelectRow(dgv, iRowKey);
}
else
{
iRowKey = iRowBefore;
}
}
}
break;
}
if (isStillSelected && toClear)
{
ClearIsSelectedByKey(iMenuBefore, iRowBefore);
}
}
private void SelectPreviousMenu(int iRowBefore, ref Menu menu, ref DataGridView dgv, DataGridView dgvBefore, ref bool toClear)
{
if (iMenuKey > 0)
{
if (menus[iMenuKey - 1] != null)
{
iMenuKey -= 1;
iRowKey = -1;
menu = menus[iMenuKey];
dgv = menu.GetDataGridView();
if (SelectMatched(dgv, dgv.SelectedRows[0].Index) ||
SelectMatched(dgv, 0))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
}
}
else
{
RowDeselected(dgvBefore, iRowBefore);
iMenuKey = 0;
iRowKey = -1;
toClear = true;
Cleared?.Invoke();
}
}
private void SelectNextMenu(int iRowBefore, ref DataGridView dgv, DataGridView dgvBefore, Menu menuFromSelected, bool isStillSelected, ref bool toClear)
{
int iMenuKeyNext = iMenuKey + 1;
if (isStillSelected)
{
if (menuFromSelected != null &&
menuFromSelected == menus[iMenuKeyNext])
{
dgv = menuFromSelected.GetDataGridView();
if (dgv.Rows.Count > 0)
{
iMenuKey += 1;
iRowKey = -1;
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
}
}
}
else
{
iRowKey = -1;
iMenuKey = menus.Where(m => m != null).Count() - 1;
if (menus[iMenuKey] != null)
{
dgv = menus[iMenuKey].GetDataGridView();
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
RowDeselected(dgvBefore, iRowBefore);
SelectRow(dgv, iRowKey);
toClear = true;
}
}
}
}
private void SelectRow(DataGridView dgv, int iRowKey)
{
InUse = true;
RowSelected(dgv, iRowKey);
}
private bool SelectMatched(DataGridView dgv, int indexStart, string keyInput = "")
{
bool found = false;
for (int i = indexStart; i < dgv.Rows.Count; i++)
{
if (Select(dgv, i, keyInput))
{
found = true;
break;
}
}
return found;
}
private bool SelectMatchedReverse(DataGridView dgv, int indexStart, string keyInput = "")
{
bool found = false;
for (int i = indexStart; i > -1; i--)
{
if (Select(dgv, i, keyInput))
{
found = true;
break;
}
}
return found;
}
private bool Select(DataGridView dgv, int i, string keyInput = "")
{
bool found = false;
if (i > -1 &&
i != iRowKey &&
dgv.Rows.Count > i)
{
DataGridViewRow row = dgv.Rows[i];
RowData rowData = (RowData)row.Cells[2].Value;
string text = row.Cells[1].Value.ToString();
if (text.StartsWith(keyInput, true, CultureInfo.InvariantCulture))
{
iRowKey = rowData.RowIndex;
rowData.IsSelected = true;
row.Selected = false;
row.Selected = true;
if (row.Index < dgv.FirstDisplayedScrollingRowIndex)
{
dgv.FirstDisplayedScrollingRowIndex = row.Index;
}
else if (row.Index >=
dgv.FirstDisplayedScrollingRowIndex +
dgv.DisplayedRowCount(false))
{
dgv.FirstDisplayedScrollingRowIndex = row.Index -
dgv.DisplayedRowCount(false) + 1;
}
found = true;
}
}
return found;
}
private void ClearIsSelectedByKey(int menuIndex, int rowIndex)
{
Menu menu = menus[menuIndex];
if (menu != null && rowIndex > -1)
{
DataGridView dgv = menu.GetDataGridView();
if (dgv.Rows.Count > rowIndex)
{
DataGridViewRow row = dgv.Rows[rowIndex];
row.Selected = false;
RowData rowData = (RowData)row.Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = false;
rowData.IsClicking = false;
}
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,270 @@
// <copyright file="MenusHelpers.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Business
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
using FSI.BT.Tools.SystemTrayMenu.Helper;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
internal static class MenusHelpers
{
internal static void GetItemsForMainMenu(BackgroundWorker worker, string path, ref MenuData menuData)
{
menuData.IsNetworkRoot = FileLnk.IsNetworkRoot(path);
if (menuData.IsNetworkRoot)
{
GetNetworkRootDirectories(path, ref menuData);
}
else
{
GetDirectories(worker, path, ref menuData);
GetFiles(worker, path, ref menuData);
}
}
internal static void GetAddionalItemsForMainMenu(ref MenuData menuData)
{
if (menuData.Level != 0)
{
return;
}
foreach (var path in GetAddionalPathsForMainMenu())
{
GetDirectoriesAndFilesRecursive(ref menuData, path.Path, path.OnlyFiles, path.Recursive);
}
}
internal static IEnumerable<(string Path, bool Recursive, bool OnlyFiles)> GetAddionalPathsForMainMenu()
{
foreach (string pathAndRecursivString in Global.Vars.SystemTrayMenuSettings.PathsAddToMainMenu.Split(@"|"))
{
if (string.IsNullOrEmpty(pathAndRecursivString))
{
continue;
}
string pathAddForMainMenu = pathAndRecursivString.Split("recursiv:")[0].Trim();
bool recursive = pathAndRecursivString.Split("recursiv:")[1].StartsWith("True");
bool onlyFiles = pathAndRecursivString.Split("onlyFiles:")[1].StartsWith("True");
yield return (Path: pathAddForMainMenu, Recursive: recursive, OnlyFiles: onlyFiles);
}
}
internal static void ReadHiddenAndReadIcons(BackgroundWorker worker, ref MenuData menuData)
{
List<RowData> rowDatasToRemove = new();
foreach (RowData rowData in menuData.RowDatas)
{
if (worker?.CancellationPending == true)
{
return;
}
if (!menuData.IsNetworkRoot && FolderOptions.IsHidden(rowData))
{
rowDatasToRemove.Add(rowData);
continue;
}
rowData.ReadIcon(true);
}
menuData.RowDatas = menuData.RowDatas.Except(rowDatasToRemove).ToList();
}
internal static void CheckIfValid(ref MenuData menuData)
{
if (menuData.Validity == MenuDataValidity.Undefined)
{
if (menuData.RowDatas.Count == 0)
{
menuData.Validity = MenuDataValidity.Empty;
}
else
{
menuData.Validity = MenuDataValidity.Valid;
}
}
}
internal static void SortItemsWhenValid(ref MenuData menuData)
{
if (menuData.Validity != MenuDataValidity.Valid)
{
return;
}
menuData.RowDatas = SortItems(menuData.RowDatas);
}
internal static List<RowData> SortItems(List<RowData> rowDatas)
{
if (Global.Vars.SystemTrayMenuSettings.SortByTypeAndNameWindowsExplorerSort)
{
rowDatas = rowDatas.OrderByDescending(x => x.IsFolder)
.ThenBy(x => x.Text, new WindowsExplorerSort()).ToList();
}
else if (Global.Vars.SystemTrayMenuSettings.SortByTypeAndDate)
{
rowDatas = rowDatas.OrderByDescending(x => x.IsFolder)
.ThenByDescending(x => x.FileInfo.LastWriteTime).ToList();
}
else if (Global.Vars.SystemTrayMenuSettings.SortByFileExtensionAndName)
{
rowDatas = rowDatas.OrderBy(x => x.FileExtension).ThenBy(x => x.Text).ToList();
}
else if (Global.Vars.SystemTrayMenuSettings.SortByName)
{
rowDatas = rowDatas.OrderBy(x => x.Text).ToList();
}
else if (Global.Vars.SystemTrayMenuSettings.SortByDate)
{
rowDatas = rowDatas.OrderByDescending(x => x.FileInfo.LastWriteTime).ToList();
}
return rowDatas;
}
private static void GetNetworkRootDirectories(string path, ref MenuData menuData)
{
Process cmd = new();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
try
{
bool resolvedSomething = false;
cmd.Start();
cmd.StandardInput.WriteLine($"net view {path}");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
string output = cmd.StandardOutput.ReadToEnd();
cmd.WaitForExit();
cmd.Close();
List<string> lines = output
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
if (lines.Count > 8)
{
foreach (string line in lines.Skip(6).SkipLast(2))
{
int indexOfFirstSpace = line.IndexOf(" ", StringComparison.InvariantCulture);
if (indexOfFirstSpace > 0)
{
string directory = Path.Combine(path, line[..indexOfFirstSpace]);
menuData.RowDatas.Add(new RowData(true, false, true, menuData.Level, directory));
resolvedSomething = true;
}
}
}
if (!resolvedSomething)
{
Log.Info($"Could not resolve network root folder: {path} , output:{output}");
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetDirectories(BackgroundWorker worker, string path, ref MenuData menuData)
{
try
{
foreach (var directory in Directory.GetDirectories(path))
{
if (worker?.CancellationPending == true)
{
return;
}
menuData.RowDatas.Add(new RowData(true, false, false, menuData.Level, directory));
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetFiles(BackgroundWorker worker, string path, ref MenuData menuData)
{
try
{
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
{
if (worker?.CancellationPending == true)
{
return;
}
menuData.RowDatas.Add(new RowData(false, false, false, menuData.Level, file));
}
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
if (ex is UnauthorizedAccessException)
{
menuData.Validity = MenuDataValidity.NoAccess;
}
}
}
private static void GetDirectoriesAndFilesRecursive(
ref MenuData menuData,
string path,
bool onlyFiles,
bool recursiv)
{
try
{
foreach (string file in DirectoryBySearchPattern.GetFiles(path, Config.SearchPattern))
{
menuData.RowDatas.Add(new RowData(false, true, false, menuData.Level, file));
}
foreach (string directory in Directory.GetDirectories(path))
{
if (!onlyFiles)
{
menuData.RowDatas.Add(new RowData(true, true, false, menuData.Level, directory));
}
if (recursiv)
{
GetDirectoriesAndFilesRecursive(ref menuData, directory, onlyFiles, recursiv);
}
}
}
catch (Exception ex)
{
Log.Warn($"GetDirectoriesAndFilesRecursive path:'{path}'", ex);
}
}
}
}

View File

@@ -0,0 +1,46 @@
// <copyright file="WaitLeave.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Handler
{
using System;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitLeave : IDisposable
{
private readonly Timer timerLeaveCheck = new();
public WaitLeave(int timeUntilTriggered)
{
timerLeaveCheck.Interval = timeUntilTriggered;
timerLeaveCheck.Tick += TimerLeaveCheckTick;
}
public event Action LeaveTriggered;
public void Dispose()
{
timerLeaveCheck.Tick -= TimerLeaveCheckTick;
timerLeaveCheck.Dispose();
}
internal void Start()
{
timerLeaveCheck.Stop();
timerLeaveCheck.Start();
}
internal void Stop()
{
timerLeaveCheck.Stop();
}
internal void TimerLeaveCheckTick(object sender, EventArgs e)
{
timerLeaveCheck.Stop();
LeaveTriggered?.Invoke();
}
}
}

View File

@@ -0,0 +1,220 @@
// <copyright file="WaitToLoadMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Handler
{
using System;
using System.Windows.Forms;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
using FSI.BT.Tools.SystemTrayMenu.UserInterface;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitToLoadMenu : IDisposable
{
private readonly Timer timerStartLoad = new();
private DataGridView dgv;
private int rowIndex;
private DataGridView dgvTmp;
private int rowIndexTmp;
private int mouseMoveEvents;
private DateTime dateTimeLastMouseMoveEvent = DateTime.Now;
private bool checkForMouseActive = true;
internal WaitToLoadMenu()
{
timerStartLoad.Interval = Global.Vars.SystemTrayMenuSettings.TimeUntilOpens;
timerStartLoad.Tick += WaitStartLoad_Tick;
}
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event Action StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
internal bool MouseActive { get; set; }
public void Dispose()
{
timerStartLoad.Tick -= WaitStartLoad_Tick;
timerStartLoad.Stop();
timerStartLoad.Dispose();
dgv?.Dispose();
dgvTmp?.Dispose();
}
internal void MouseEnter(object sender, DataGridViewCellEventArgs e)
{
if (MouseActive)
{
DataGridView dgv = (DataGridView)sender;
if (dgv.Rows.Count > e.RowIndex)
{
MouseEnterOk(dgv, e.RowIndex);
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
checkForMouseActive = true;
SetData(dgv, e.RowIndex);
timerStartLoad.Start();
}
}
else
{
dgvTmp = (DataGridView)sender;
rowIndexTmp = e.RowIndex;
}
}
internal void RowSelected(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
SetData(dgv, rowIndex);
MouseActive = false;
checkForMouseActive = false;
timerStartLoad.Start();
}
}
internal void MouseLeave(object sender, DataGridViewCellEventArgs e)
{
if (MouseActive)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData((DataGridView)sender, e.RowIndex);
}
}
internal void RowDeselected(DataGridView dgv, int rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData(dgv, rowIndex);
MouseActive = false;
}
internal void ClickOpensInstantly(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
SetData(dgv, rowIndex);
MouseActive = true;
checkForMouseActive = false;
CallOpenMenuNow();
}
}
internal void EnterOpensInstantly(DataGridView dgv, int rowIndex)
{
if (dgv.Rows.Count > rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
SetData(dgv, rowIndex);
MouseActive = false;
checkForMouseActive = false;
CallOpenMenuNow();
}
}
internal void MouseMove(object sender, MouseEventArgs e)
{
if (!MouseActive)
{
if (mouseMoveEvents > 6)
{
MouseActive = true;
if (dgvTmp != null && !dgvTmp.IsDisposed)
{
MouseEnter(dgvTmp, new DataGridViewCellEventArgs(
0, rowIndexTmp));
}
mouseMoveEvents = 0;
}
else if (DateTime.Now - dateTimeLastMouseMoveEvent <
new TimeSpan(0, 0, 0, 0, 200))
{
mouseMoveEvents++;
}
else
{
dateTimeLastMouseMoveEvent = DateTime.Now;
mouseMoveEvents = 0;
}
}
}
private void WaitStartLoad_Tick(object sender, EventArgs e)
{
timerStartLoad.Stop();
if (!checkForMouseActive || MouseActive)
{
CallOpenMenuNow();
}
}
private void CallOpenMenuNow()
{
if (dgv.Rows.Count > rowIndex)
{
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
Menu menu = (Menu)dgv.FindForm();
rowData.Level = menu.Level;
if (rowData.ContainsMenu)
{
CloseMenu.Invoke(rowData.Level + 2);
}
CloseMenu.Invoke(rowData.Level + 1);
if (!rowData.IsContextMenuOpen &&
rowData.ContainsMenu &&
rowData.Level + 1 < MenuDefines.MenusMax)
{
StartLoadMenu.Invoke(rowData);
}
}
}
private void SetData(DataGridView dgv, int rowIndex)
{
dgvTmp = null;
this.dgv = dgv;
this.rowIndex = rowIndex;
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = true;
}
dgv.Rows[rowIndex].Selected = false;
dgv.Rows[rowIndex].Selected = true;
}
private void ResetData(DataGridView dgv, int rowIndex)
{
if (dgv != null && dgv.Rows.Count > rowIndex)
{
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = false;
rowData.IsClicking = false;
dgv.Rows[rowIndex].Selected = false;
this.dgv = null;
this.rowIndex = 0;
}
}
}
}
}

View File

@@ -0,0 +1,95 @@
// <copyright file="AppColors.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu
{
using System.Drawing;
internal static class AppColors
{
public static Color Arrow { get; internal set; }
public static Color ArrowHoverBackground { get; internal set; }
public static Color ArrowHover { get; internal set; }
public static Color ArrowClick { get; internal set; }
public static Color ArrowClickBackground { get; internal set; }
public static Color SliderArrowsAndTrackHover { get; internal set; }
public static Color Slider { get; internal set; }
public static Color SliderHover { get; internal set; }
public static Color SliderDragging { get; internal set; }
public static Color ScrollbarBackground { get; internal set; }
public static Color ArrowDarkMode { get; internal set; }
public static Color ArrowHoverBackgroundDarkMode { get; internal set; }
public static Color ArrowHoverDarkMode { get; internal set; }
public static Color ArrowClickDarkMode { get; internal set; }
public static Color ArrowClickBackgroundDarkMode { get; internal set; }
public static Color SliderArrowsAndTrackHoverDarkMode { get; internal set; }
public static Color SliderDarkMode { get; internal set; }
public static Color SliderHoverDarkMode { get; internal set; }
public static Color SliderDraggingDarkMode { get; internal set; }
public static Color ScrollbarBackgroundDarkMode { get; internal set; }
public static Color SelectedItem { get; set; }
public static Color DarkModeSelecetedItem { get; set; }
public static Color SelectedItemBorder { get; set; }
public static Color DarkModeSelectedItemBorder { get; set; }
public static Color OpenFolder { get; set; }
public static Color DarkModeOpenFolder { get; set; }
public static Color OpenFolderBorder { get; set; }
public static Color DarkModeOpenFolderBorder { get; set; }
public static Color Background { get; set; }
public static Color DarkModeBackground { get; set; }
public static Color BackgroundBorder { get; set; }
public static Color DarkModeBackgroundBorder { get; set; }
public static Color SearchField { get; set; }
public static Color DarkModeSearchField { get; set; }
public static Bitmap BitmapOpenFolder { get; set; }
public static Bitmap BitmapPin { get; set; }
public static Bitmap BitmapSettings { get; set; }
public static Bitmap BitmapRestart { get; set; }
public static Bitmap BitmapPinActive { get; set; }
public static Bitmap BitmapSearch { get; set; }
public static Color Icons { get; set; }
public static Color DarkModeIcons { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
// <copyright file="ColorAndCode.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu
{
using System.Drawing;
internal struct ColorAndCode
{
public Color Color { get; set; }
public string HtmlColorCode { get; set; }
}
}

View File

@@ -0,0 +1,531 @@
// <copyright file="Config.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu
{
using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using FSI.BT.Tools.Global.UserInterface.FolderBrowseDialog;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.Properties;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using Microsoft.Win32;
using Svg;
using static FSI.BT.Tools.SystemTrayMenu.Utilities.IconReader;
public static class Config
{
private static readonly Icon SystemTrayMenu = new Icon(Properties.Resources.SystemTrayMenu, SystemInformation.SmallIconSize);
private static readonly Icon IconRootFolder = GetIconSTA(Path, Path, false, IconSize.Small, true);
private static bool readDarkModeDone;
private static bool isDarkMode;
private static bool readHideFileExtdone;
private static bool isHideFileExtension;
public static string Path =>Global.Vars.SystemTrayMenuSettings.PathDirectory;
public static string SearchPattern => Global.Vars.SystemTrayMenuSettings.SearchPattern;
public static bool ShowDirectoryTitleAtTop => Global.Vars.SystemTrayMenuSettings.ShowDirectoryTitleAtTop;
public static bool ShowSearchBar => Global.Vars.SystemTrayMenuSettings.ShowSearchBar;
public static bool ShowCountOfElementsBelow => Global.Vars.SystemTrayMenuSettings.ShowCountOfElementsBelow;
public static bool ShowFunctionKeyOpenFolder => Global.Vars.SystemTrayMenuSettings.ShowFunctionKeyOpenFolder;
public static bool ShowFunctionKeyPinMenu => Global.Vars.SystemTrayMenuSettings.ShowFunctionKeyPinMenu;
public static bool ShowFunctionKeySettings => Global.Vars.SystemTrayMenuSettings.ShowFunctionKeySettings;
public static bool ShowFunctionKeyRestart => Global.Vars.SystemTrayMenuSettings.ShowFunctionKeyRestart;
public static bool AlwaysOpenByPin { get; internal set; }
public static void Initialize()
{
UpgradeIfNotUpgraded();
InitializeColors();
if (string.IsNullOrEmpty(Global.Vars.SystemTrayMenuSettings.PathIcoDirectory))
{
Global.Vars.SystemTrayMenuSettings.PathIcoDirectory = System.IO.Path.Combine(
System.IO.Path.Combine(
Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData), $"FSI.BT.Tools.SystemTrayMenu"), "ico");
if (!Directory.Exists(Global.Vars.SystemTrayMenuSettings.PathIcoDirectory))
{
Directory.CreateDirectory(Global.Vars.SystemTrayMenuSettings.PathIcoDirectory);
}
}
}
public static void Dispose()
{
AppColors.BitmapOpenFolder.Dispose();
AppColors.BitmapPin.Dispose();
AppColors.BitmapPinActive.Dispose();
AppColors.BitmapSettings.Dispose();
AppColors.BitmapRestart.Dispose();
AppColors.BitmapSearch.Dispose();
}
public static Icon GetAppIcon()
{
if (Global.Vars.SystemTrayMenuSettings.UseIconFromRootFolder)
{
return IconRootFolder;
}
else
{
return SystemTrayMenu;
}
}
public static void SetFolderByWindowsContextMenu(string[] args)
{
if (args != null && args.Length > 0 && args[0] != "-r")
{
string path = args[0];
Log.Info($"SetFolderByWindowsContextMenu() path: {path}");
Global.Vars.SystemTrayMenuSettings.PathDirectory = path;
//Global.Vars.SystemTrayMenuSettings.Save();
}
}
public static void LoadOrSetByUser()
{
if (string.IsNullOrEmpty(Path))
{
string textFirstStart = Global.Utilities.Translator.GetText(
"Read the FAQ and then choose a root directory for SystemTrayMenu.");
MessageBox.Show(
textFirstStart,
"SystemTrayMenu",
MessageBoxButtons.OK);
ShowHelpFAQ();
SetFolderByUser();
}
}
public static void SetFolderByUser(bool save = true)
{
using FolderDialog dialog = new();
dialog.InitialFolder = Path;
if (dialog.ShowDialog() == DialogResult.OK)
{
Global.Vars.SystemTrayMenuSettings.PathDirectory = dialog.Folder;
//if (save)
//{
// Global.Vars.SystemTrayMenuSettings.Save();
//}
}
}
public static void SetFolderIcoByUser()
{
using FolderDialog dialog = new();
dialog.InitialFolder = Global.Vars.SystemTrayMenuSettings.PathIcoDirectory;
if (dialog.ShowDialog() == DialogResult.OK)
{
Global.Vars.SystemTrayMenuSettings.PathIcoDirectory = dialog.Folder;
}
}
internal static void ShowHelpFAQ()
{
Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu#FAQ");
}
internal static void ShowSupportSystemTrayMenu()
{
Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu#donations");
}
/// <summary>
/// Read the OS setting whether dark mode is enabled.
/// </summary>
/// <returns>true = Dark mode; false = Light mode.</returns>
internal static bool IsDarkMode()
{
if (!readDarkModeDone)
{
// 0 = Dark mode, 1 = Light mode
if (Global.Vars.SystemTrayMenuSettings.IsDarkModeAlwaysOn ||
IsRegistryValueThisValue(
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
"AppsUseLightTheme",
"0"))
{
isDarkMode = true;
}
readDarkModeDone = true;
}
return isDarkMode;
}
internal static void ResetReadDarkModeDone()
{
isDarkMode = false;
readDarkModeDone = false;
}
/// <summary>
/// Read the OS setting whether HideFileExt enabled.
/// </summary>
/// <returns>isHideFileExtension.</returns>
internal static bool IsHideFileExtension()
{
if (!readHideFileExtdone)
{
// 0 = To show extensions, 1 = To hide extensions
if (IsRegistryValueThisValue(
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced",
"HideFileExt",
"1"))
{
isHideFileExtension = true;
}
readHideFileExtdone = true;
}
return isHideFileExtension;
}
internal static void InitializeColors(bool save = true)
{
ColorConverter converter = new();
ColorAndCode colorAndCode = default;
bool changed = false;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSelectedItem;
colorAndCode.Color = Color.FromArgb(204, 232, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSelectedItem = colorAndCode.HtmlColorCode;
AppColors.SelectedItem = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeSelecetedItem;
colorAndCode.Color = Color.FromArgb(51, 51, 51);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeSelecetedItem = colorAndCode.HtmlColorCode;
AppColors.DarkModeSelecetedItem = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSelectedItemBorder;
colorAndCode.Color = Color.FromArgb(153, 209, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSelectedItemBorder = colorAndCode.HtmlColorCode;
AppColors.SelectedItemBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeSelectedItemBorder;
colorAndCode.Color = Color.FromArgb(20, 29, 75);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeSelectedItemBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeSelectedItemBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorOpenFolder;
colorAndCode.Color = Color.FromArgb(194, 245, 222);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorOpenFolder = colorAndCode.HtmlColorCode;
AppColors.OpenFolder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeOpenFolder;
colorAndCode.Color = Color.FromArgb(20, 65, 42);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeOpenFolder = colorAndCode.HtmlColorCode;
AppColors.DarkModeOpenFolder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorOpenFolderBorder;
colorAndCode.Color = Color.FromArgb(153, 255, 165);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorOpenFolderBorder = colorAndCode.HtmlColorCode;
AppColors.OpenFolderBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeOpenFolderBorder;
colorAndCode.Color = Color.FromArgb(20, 75, 85);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeOpenFolderBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeOpenFolderBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorIcons;
colorAndCode.Color = Color.FromArgb(149, 160, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorIcons = colorAndCode.HtmlColorCode;
AppColors.Icons = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeIcons;
colorAndCode.Color = Color.FromArgb(149, 160, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeIcons = colorAndCode.HtmlColorCode;
AppColors.DarkModeIcons = colorAndCode.Color;
string htmlColorCodeIcons;
if (IsDarkMode())
{
htmlColorCodeIcons = Global.Vars.SystemTrayMenuSettings.ColorDarkModeIcons;
}
else
{
htmlColorCodeIcons = Global.Vars.SystemTrayMenuSettings.ColorIcons;
}
AppColors.BitmapOpenFolder =
ReadSvg(Properties.Resources.ic_fluent_folder_arrow_right_48_regular, htmlColorCodeIcons);
AppColors.BitmapPin =
ReadSvg(Properties.Resources.ic_fluent_pin_48_regular, htmlColorCodeIcons);
AppColors.BitmapSettings =
ReadSvg(Properties.Resources.ic_fluent_settings_28_regular, htmlColorCodeIcons);
AppColors.BitmapRestart =
ReadSvg(Properties.Resources.ic_fluent_arrow_sync_24_regular, htmlColorCodeIcons);
AppColors.BitmapPinActive =
ReadSvg(Properties.Resources.ic_fluent_pin_48_filled, htmlColorCodeIcons);
AppColors.BitmapSearch =
ReadSvg(Properties.Resources.ic_fluent_search_48_regular, htmlColorCodeIcons);
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSearchField;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSearchField = colorAndCode.HtmlColorCode;
AppColors.SearchField = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeSearchField;
colorAndCode.Color = Color.FromArgb(25, 25, 25);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeSearchField = colorAndCode.HtmlColorCode;
AppColors.DarkModeSearchField = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorBackground;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorBackground = colorAndCode.HtmlColorCode;
AppColors.Background = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeBackground;
colorAndCode.Color = Color.FromArgb(32, 32, 32);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeBackground = colorAndCode.HtmlColorCode;
AppColors.DarkModeBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorBackgroundBorder;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorBackgroundBorder = colorAndCode.HtmlColorCode;
AppColors.BackgroundBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorDarkModeBackgroundBorder;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorDarkModeBackgroundBorder = colorAndCode.HtmlColorCode;
AppColors.DarkModeBackgroundBorder = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrow;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrow = colorAndCode.HtmlColorCode;
AppColors.Arrow = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowHoverBackground;
colorAndCode.Color = Color.FromArgb(218, 218, 218);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowHoverBackground = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowHover;
colorAndCode.Color = Color.FromArgb(0, 0, 0);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowHover = colorAndCode.HtmlColorCode;
AppColors.ArrowHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowClick;
colorAndCode.Color = Color.FromArgb(255, 255, 255);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowClick = colorAndCode.HtmlColorCode;
AppColors.ArrowClick = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowClickBackground;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowClickBackground = colorAndCode.HtmlColorCode;
AppColors.ArrowClickBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderArrowsAndTrackHover;
colorAndCode.Color = Color.FromArgb(192, 192, 192);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderArrowsAndTrackHover = colorAndCode.HtmlColorCode;
AppColors.SliderArrowsAndTrackHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSlider;
colorAndCode.Color = Color.FromArgb(205, 205, 205);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSlider = colorAndCode.HtmlColorCode;
AppColors.Slider = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderHover;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderHover = colorAndCode.HtmlColorCode;
AppColors.SliderHover = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderDragging;
colorAndCode.Color = Color.FromArgb(96, 96, 96);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderDragging = colorAndCode.HtmlColorCode;
AppColors.SliderDragging = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorScrollbarBackground;
colorAndCode.Color = Color.FromArgb(240, 240, 240);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorScrollbarBackground = colorAndCode.HtmlColorCode;
AppColors.ScrollbarBackground = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowDarkMode;
colorAndCode.Color = Color.FromArgb(103, 103, 103);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowHoverBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(55, 55, 55);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowHoverBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverBackgroundDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowHoverDarkMode;
colorAndCode.Color = Color.FromArgb(103, 103, 103);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowClickDarkMode;
colorAndCode.Color = Color.FromArgb(23, 23, 23);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowClickDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowClickDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorArrowClickBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorArrowClickBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ArrowClickBackgroundDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderArrowsAndTrackHoverDarkMode;
colorAndCode.Color = Color.FromArgb(77, 77, 77);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderArrowsAndTrackHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderArrowsAndTrackHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderDarkMode;
colorAndCode.Color = Color.FromArgb(77, 77, 77);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderHoverDarkMode;
colorAndCode.Color = Color.FromArgb(122, 122, 122);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderHoverDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderHoverDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorSliderDraggingDarkMode;
colorAndCode.Color = Color.FromArgb(166, 166, 166);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorSliderDraggingDarkMode = colorAndCode.HtmlColorCode;
AppColors.SliderDraggingDarkMode = colorAndCode.Color;
colorAndCode.HtmlColorCode = Global.Vars.SystemTrayMenuSettings.ColorScrollbarBackgroundDarkMode;
colorAndCode.Color = Color.FromArgb(23, 23, 23);
colorAndCode = ProcessColorAndCode(converter, colorAndCode, ref changed);
Global.Vars.SystemTrayMenuSettings.ColorScrollbarBackgroundDarkMode = colorAndCode.HtmlColorCode;
AppColors.ScrollbarBackgroundDarkMode = colorAndCode.Color;
//if (save && changed)
//{
// Global.Vars.SystemTrayMenuSettings.Save();
//}
}
private static Bitmap ReadSvg(byte[] byteArray, string htmlColorCode)
{
string str = Encoding.UTF8.GetString(byteArray);
str = str.Replace("#585858", htmlColorCode);
byteArray = Encoding.UTF8.GetBytes(str);
using MemoryStream stream = new(byteArray);
SvgDocument svgDocument = SvgDocument.Open<SvgDocument>(stream);
svgDocument.Color = new SvgColourServer(Color.Black);
return svgDocument.Draw();
}
private static bool IsRegistryValueThisValue(string keyName, string valueName, string value)
{
bool isRegistryValueThisValue = false;
try
{
object registryHideFileExt = Registry.GetValue(keyName, valueName, 1);
if (registryHideFileExt == null)
{
Log.Info($"Could not read registry keyName:{keyName} valueName:{valueName}");
}
else if (registryHideFileExt.ToString() == value)
{
isRegistryValueThisValue = true;
}
}
catch (Exception ex)
{
if (ex is System.Security.SecurityException ||
ex is IOException)
{
Log.Warn($"Could not read registry keyName:{keyName} valueName:{valueName}", ex);
}
else
{
throw;
}
}
return isRegistryValueThisValue;
}
private static void UpgradeIfNotUpgraded()
{
//if (!Global.Vars.SystemTrayMenuSettings.IsUpgraded)
//{
// Global.Vars.SystemTrayMenuSettings.Upgrade();
// Global.Vars.SystemTrayMenuSettings.IsUpgraded = true;
// Global.Vars.SystemTrayMenuSettings.Save();
// Log.Info($"Settings upgraded from {CustomSettingsProvider.UserConfigPath}");
//}
}
private static ColorAndCode ProcessColorAndCode(
ColorConverter colorConverter,
ColorAndCode colorAndCode,
ref bool changedHtmlColorCode)
{
try
{
colorAndCode.Color = (Color)colorConverter.ConvertFromString(colorAndCode.HtmlColorCode);
}
catch (ArgumentException ex)
{
Log.Warn($"HtmlColorCode {colorAndCode.HtmlColorCode}", ex);
colorAndCode.HtmlColorCode = ColorTranslator.ToHtml(colorAndCode.Color);
changedHtmlColorCode = true;
}
return colorAndCode;
}
}
}

View File

@@ -0,0 +1,90 @@
// <copyright file="MenuDefines.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu
{
using System.Drawing;
internal static class MenuDefines
{
internal const int MenusMax = 50;
internal const int LengthMax = 37;
internal const int Scrollspeed = 3;
public static Color ColorSelectedItem
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeSelecetedItem;
}
else
{
return AppColors.SelectedItem;
}
}
}
public static Color ColorSelectedItemBorder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeSelectedItemBorder;
}
else
{
return AppColors.SelectedItemBorder;
}
}
}
public static Color ColorOpenFolder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeOpenFolder;
}
else
{
return AppColors.OpenFolder;
}
}
}
public static Color ColorOpenFolderBorder
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeOpenFolderBorder;
}
else
{
return AppColors.OpenFolderBorder;
}
}
}
public static Color ColorIcons
{
get
{
if (Config.IsDarkMode())
{
return AppColors.DarkModeIcons;
}
else
{
return AppColors.Icons;
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
// <copyright file="MenuData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.DataClasses
{
using System.Collections.Generic;
internal enum MenuDataValidity
{
Undefined,
Valid,
Empty,
NoAccess,
}
internal struct MenuData
{
public MenuData(int level)
{
RowDatas = new List<RowData>();
Validity = MenuDataValidity.Undefined;
Level = level;
RowDataParent = null;
IsNetworkRoot = false;
}
internal List<RowData> RowDatas { get; set; }
internal MenuDataValidity Validity { get; set; }
internal int Level { get; }
internal RowData RowDataParent { get; set; }
internal bool IsNetworkRoot { get; set; }
}
}

View File

@@ -0,0 +1,303 @@
// <copyright file="RowData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.DataClasses
{
using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.IconReader;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class RowData
{
private static DateTime contextMenuClosed;
private Icon icon;
/// <summary>
/// Initializes a new instance of the <see cref="RowData"/> class.
/// empty dummy.
/// </summary>
internal RowData()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RowData"/> class.
/// (Related replace "\x00" see #171.)
/// </summary>
/// <param name="isFolder">Flag if file or folder.</param>
/// <param name="isAddionalItem">Flag if addional item, from other folder than root folder.</param>
/// <param name="isNetworkRoot">Flag if resolved from network root folder.</param>
/// <param name="level">The number of the menu level.</param>
/// <param name="path">Path to item.</param>
internal RowData(bool isFolder, bool isAddionalItem, bool isNetworkRoot, int level, string path)
{
IsFolder = isFolder;
IsAddionalItem = isAddionalItem;
IsNetworkRoot = isNetworkRoot;
Level = level;
try
{
FileInfo = new FileInfo(path.Replace("\x00", string.Empty));
Path = IsFolder ? $@"{FileInfo.FullName}\" : FileInfo.FullName;
FileExtension = System.IO.Path.GetExtension(Path);
IsLink = FileExtension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase);
if (IsLink)
{
ResolvedPath = FileLnk.GetResolvedFileName(Path, out bool isLinkToFolder);
IsLinkToFolder = isLinkToFolder || FileLnk.IsNetworkRoot(ResolvedPath);
ShowOverlay = Global.Vars.SystemTrayMenuSettings.ShowLinkOverlay;
Text = System.IO.Path.GetFileNameWithoutExtension(Path);
if (string.IsNullOrEmpty(ResolvedPath))
{
Log.Info($"Resolved path is empty: '{Path}'");
ResolvedPath = Path;
}
}
else
{
ResolvedPath = Path;
if (string.IsNullOrEmpty(FileInfo.Name))
{
int nameBegin = FileInfo.FullName.LastIndexOf(@"\", StringComparison.InvariantCulture) + 1;
Text = FileInfo.FullName[nameBegin..];
}
else if (FileExtension.Equals(".url", StringComparison.InvariantCultureIgnoreCase) ||
FileExtension.Equals(".appref-ms", StringComparison.InvariantCultureIgnoreCase))
{
ShowOverlay = Global.Vars.SystemTrayMenuSettings.ShowLinkOverlay;
Text = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name);
}
else if (!IsFolder && Config.IsHideFileExtension())
{
Text = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name);
}
else
{
Text = FileInfo.Name;
}
}
ContainsMenu = IsFolder;
if (Global.Vars.SystemTrayMenuSettings.ResolveLinksToFolders)
{
ContainsMenu |= IsLinkToFolder;
}
IsMainMenu = Level == 0;
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
}
}
internal FileInfo FileInfo { get; }
internal string Path { get; }
internal bool IsFolder { get; }
internal bool IsAddionalItem { get; }
internal bool IsNetworkRoot { get; }
internal int Level { get; set; }
internal string FileExtension { get; }
internal bool IsLink { get; }
internal string ResolvedPath { get; }
internal bool IsLinkToFolder { get; }
internal bool ShowOverlay { get; }
internal string Text { get; }
internal bool ContainsMenu { get; }
internal bool IsMainMenu { get; }
internal Menu SubMenu { get; set; }
internal bool IsMenuOpen { get; set; }
internal bool IsClicking { get; set; }
internal bool IsSelected { get; set; }
internal bool IsContextMenuOpen { get; set; }
internal bool HiddenEntry { get; set; }
internal int RowIndex { get; set; }
internal bool IconLoading { get; set; }
internal bool ProcessStarted { get; set; }
internal void SetData(RowData data, DataTable dataTable)
{
DataRow row = dataTable.Rows.Add();
data.RowIndex = dataTable.Rows.IndexOf(row);
if (HiddenEntry)
{
row[0] = AddIconOverlay(data.icon, Properties.Resources.White50Percentage);
}
else
{
row[0] = data.icon;
}
row[1] = data.Text;
row[2] = data;
}
internal Icon ReadIcon(bool updateIconInBackground)
{
if (IsFolder || IsLinkToFolder)
{
icon = GetFolderIconWithCache(Path, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
IconLoading = loading;
}
else
{
icon = GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, updateIconInBackground, IsMainMenu, out bool loading);
IconLoading = loading;
}
if (!IconLoading)
{
if (icon == null)
{
icon = Properties.Resources.NotFound;
}
else if (HiddenEntry)
{
icon = AddIconOverlay(icon, Properties.Resources.White50Percentage);
}
}
return icon;
}
internal void MouseDown(DataGridView dgv, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
IsClicking = true;
}
if (e != null &&
e.Button == MouseButtons.Right &&
FileInfo != null &&
dgv != null &&
dgv.Rows.Count > RowIndex &&
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
{
IsContextMenuOpen = true;
ShellContextMenu ctxMnu = new();
Point location = dgv.FindForm().Location;
Point point = new(
e.X + location.X + dgv.Location.X,
e.Y + location.Y + dgv.Location.Y);
if (ContainsMenu)
{
DirectoryInfo[] dir = new DirectoryInfo[1];
dir[0] = new DirectoryInfo(Path);
ctxMnu.ShowContextMenu(dir, point);
TriggerFileWatcherChangeWorkaround();
}
else
{
FileInfo[] arrFI = new FileInfo[1];
arrFI[0] = FileInfo;
ctxMnu.ShowContextMenu(arrFI, point);
TriggerFileWatcherChangeWorkaround();
}
IsContextMenuOpen = false;
contextMenuClosed = DateTime.Now;
}
void TriggerFileWatcherChangeWorkaround()
{
try
{
string parentFolder = System.IO.Path.GetDirectoryName(Path);
Directory.GetFiles(parentFolder);
}
catch (Exception ex)
{
Log.Warn($"{nameof(TriggerFileWatcherChangeWorkaround)} '{Path}'", ex);
}
}
}
internal void MouseClick(MouseEventArgs e, out bool toCloseByDoubleClick)
{
IsClicking = false;
toCloseByDoubleClick = false;
if (Global.Vars.SystemTrayMenuSettings.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (Global.Vars.SystemTrayMenuSettings.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart(Path);
if (!Global.Vars.SystemTrayMenuSettings.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
}
}
internal void DoubleClick(MouseEventArgs e, out bool toCloseByDoubleClick)
{
IsClicking = false;
toCloseByDoubleClick = false;
if (!Global.Vars.SystemTrayMenuSettings.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (!Global.Vars.SystemTrayMenuSettings.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart(Path);
if (!Global.Vars.SystemTrayMenuSettings.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
}
}
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
{
if (!ContainsMenu &&
(e == null || e.Button == MouseButtons.Left))
{
ProcessStarted = true;
string workingDirectory = System.IO.Path.GetDirectoryName(ResolvedPath);
Log.ProcessStart(Path, string.Empty, false, workingDirectory, true, ResolvedPath);
if (!Global.Vars.SystemTrayMenuSettings.StaysOpenWhenItemClicked)
{
toCloseByOpenItem = true;
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
// <copyright file="DgvMouseRow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
public class DgvMouseRow : IDisposable
{
private readonly Timer timerRaiseRowMouseLeave = new();
private DataGridView dgv;
private DataGridViewCellEventArgs eventArgs;
internal DgvMouseRow()
{
timerRaiseRowMouseLeave.Interval = 200;
timerRaiseRowMouseLeave.Tick += TimerRaiseRowMouseLeave_Tick;
}
~DgvMouseRow() // the finalizer
{
Dispose(false);
}
internal event Action<object, DataGridViewCellEventArgs> RowMouseEnter;
internal event Action<object, DataGridViewCellEventArgs> RowMouseLeave;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
internal void CellMouseEnter(object sender, DataGridViewCellEventArgs newEventArgs)
{
DataGridView newDgv = (DataGridView)sender;
if (dgv != newDgv || newEventArgs.RowIndex != eventArgs.RowIndex)
{
if (timerRaiseRowMouseLeave.Enabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
TriggerRowMouseEnter(newDgv, newEventArgs);
}
else
{
timerRaiseRowMouseLeave.Stop();
}
dgv = newDgv;
eventArgs = newEventArgs;
}
internal void CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
timerRaiseRowMouseLeave.Start();
}
internal void MouseLeave(object sender, EventArgs e)
{
if (timerRaiseRowMouseLeave.Enabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timerRaiseRowMouseLeave.Tick -= TimerRaiseRowMouseLeave_Tick;
timerRaiseRowMouseLeave.Dispose();
dgv = null;
}
}
private void TimerRaiseRowMouseLeave_Tick(object sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
private void TriggerRowMouseLeave()
{
if (dgv != null)
{
RowMouseLeave?.Invoke(dgv, eventArgs);
}
dgv = null;
eventArgs = null;
}
private void TriggerRowMouseEnter(DataGridView dgv, DataGridViewCellEventArgs e)
{
RowMouseEnter?.Invoke(dgv, e);
}
}
}

View File

@@ -0,0 +1,191 @@
// <copyright file="DragDropHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
using FSI.BT.Tools.SystemTrayMenu.UserInterface;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
public static class DragDropHelper
{
public static void DragEnter(object sender, DragEventArgs e)
{
object data = e.Data.GetData("UniformResourceLocator");
if (data is MemoryStream memoryStream)
{
byte[] bytes = memoryStream.ToArray();
Encoding encod = Encoding.ASCII;
string url = encod.GetString(bytes);
if (!string.IsNullOrEmpty(url))
{
e.Effect = DragDropEffects.Copy;
}
}
}
public static void DragDrop(object sender, DragEventArgs e)
{
Menu menu = (Menu)sender;
string path;
if (menu != null)
{
RowData rowData = (RowData)menu.Tag;
if (rowData != null)
{
path = rowData.ResolvedPath;
}
else
{
path = Config.Path;
}
}
else
{
path = Config.Path;
}
object data = e.Data.GetData("UniformResourceLocator");
MemoryStream ms = data as MemoryStream;
byte[] bytes = ms.ToArray();
Encoding encod = Encoding.ASCII;
string url = encod.GetString(bytes);
new Thread(CreateShortcutInBackground).Start();
void CreateShortcutInBackground()
{
CreateShortcut(url.Replace("\0", string.Empty), path);
}
}
private static void CreateShortcut(string url, string pathToStoreFile)
{
string title = GetUrlShortcutTitle(url);
string fileNamePathShortcut = pathToStoreFile + "\\" + title.Trim() + ".url";
WriteShortcut(url, null, fileNamePathShortcut);
string pathIcon = DownloadUrlIcon(url);
if (!string.IsNullOrEmpty(pathIcon))
{
WriteShortcut(url, pathIcon, fileNamePathShortcut);
}
}
private static string GetUrlShortcutTitle(string url)
{
string title = url
.Replace("/", " ")
.Replace("https", string.Empty)
.Replace("http", string.Empty);
string invalid =
new string(Path.GetInvalidFileNameChars()) +
new string(Path.GetInvalidPathChars());
foreach (char character in invalid)
{
title = title.Replace(character.ToString(), string.Empty);
}
title = Truncate(title, 128); // max 255
return title;
}
private static string Truncate(string value, int maxLength)
{
if (!string.IsNullOrEmpty(value) &&
value.Length > maxLength)
{
value = value[..maxLength];
}
return value;
}
private static void WriteShortcut(string url, string pathIcon, string fileNamePathShortcut)
{
try
{
if (File.Exists(fileNamePathShortcut))
{
File.Delete(fileNamePathShortcut);
}
StreamWriter writer = new(fileNamePathShortcut);
writer.WriteLine("[InternetShortcut]");
writer.WriteLine($"URL={url.TrimEnd('\0')}");
writer.WriteLine("IconIndex=0");
writer.WriteLine($"HotKey=0");
writer.WriteLine($"IDList=");
if (!string.IsNullOrEmpty(pathIcon))
{
writer.WriteLine($"IconFile={pathIcon}");
}
writer.Flush();
writer.Close();
}
catch (Exception ex)
{
Log.Warn($"{nameof(WriteShortcut)} failed", ex);
}
}
private static string DownloadUrlIcon(string url)
{
string pathIcon = string.Empty;
string pathToStoreIcons = Global.Vars.SystemTrayMenuSettings.PathIcoDirectory;
Uri uri = new(url);
string hostname = uri.Host.ToString();
string pathIconPng = Path.Combine(pathToStoreIcons, $"{hostname}.png");
string urlGoogleIconDownload = @"http://www.google.com/s2/favicons?sz=32&domain=" + url;
HttpClient client = new();
try
{
if (!Directory.Exists(pathToStoreIcons))
{
Directory.CreateDirectory(pathToStoreIcons);
}
using HttpResponseMessage response = client.GetAsync(urlGoogleIconDownload).Result;
using HttpContent content = response.Content;
Stream stream = content.ReadAsStreamAsync().Result;
using var fileStream = File.Create(pathIconPng);
stream.Seek(0, SeekOrigin.Begin);
stream.CopyTo(fileStream);
fileStream.Close();
pathIcon = Path.Combine(pathToStoreIcons, $"{hostname}.ico");
if (!ImagingHelper.ConvertToIcon(pathIconPng, pathIcon, 32))
{
Log.Info("Failed to convert icon.");
}
}
catch (Exception ex)
{
Log.Warn($"{nameof(DownloadUrlIcon)} failed", ex);
}
try
{
if (File.Exists(pathIconPng))
{
File.Delete(pathIconPng);
}
}
catch (Exception ex)
{
Log.Warn($"{nameof(DownloadUrlIcon)} failed to delete {pathIconPng}", ex);
}
return pathIcon;
}
}
}

View File

@@ -0,0 +1,183 @@
// <copyright file="Fading.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
public class Fading : IDisposable
{
private const int Interval100FPS = 10; // 100fps=>1s/100fps=~10ms
private const double StepIn = 0.20;
private const double StepOut = 0.10;
private const double Transparent = 0.80;
private const double TransparentMinus = 0.60; // Transparent - StepIn
private const double TransparentPlus = 0.85; // Transparent + StepOut
private const double Shown = 1.00;
private const double ShownMinus = 0.80; // Shown - StepIn
private readonly Timer timer = new();
private FadingState state = FadingState.Idle;
private double opacity;
private bool visible;
internal Fading()
{
timer.Interval = Interval100FPS;
timer.Tick += Timer_Tick;
}
~Fading() // the finalizer
{
Dispose(false);
}
internal event Action Hide;
internal event Action Show;
internal event Action<double> ChangeOpacity;
internal enum FadingState
{
Idle,
Show,
ShowTransparent,
Hide,
}
internal bool IsHiding => state == FadingState.Hide;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
internal void Fade(FadingState state)
{
StartStopTimer(state);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timer.Tick -= Timer_Tick;
timer.Dispose();
}
}
private void StartStopTimer(FadingState newState)
{
if (newState == FadingState.Idle)
{
state = newState;
timer.Stop();
}
else
{
state = newState;
timer.Start();
}
}
private void Timer_Tick(object sender, EventArgs e)
{
FadeStep();
}
private void FadeStep()
{
switch (state)
{
case FadingState.Show:
if (!visible)
{
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(opacity);
}
else if (Global.Vars.SystemTrayMenuSettings.UseFading &&
opacity < ShownMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(opacity);
}
else
{
if (!Global.Vars.SystemTrayMenuSettings.UseFading)
{
// #393 provoke a redraw for the CS_DROPSHADOW to work
opacity = ShownMinus;
ChangeOpacity?.Invoke(opacity);
}
opacity = Shown;
ChangeOpacity?.Invoke(opacity);
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.ShowTransparent:
if (!visible)
{
visible = true;
Show?.Invoke();
opacity = 0;
ChangeOpacity?.Invoke(opacity);
}
else if (Global.Vars.SystemTrayMenuSettings.UseFading &&
opacity < TransparentMinus)
{
opacity += StepIn;
ChangeOpacity?.Invoke(opacity);
}
else if (Global.Vars.SystemTrayMenuSettings.UseFading &&
opacity > TransparentPlus)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(opacity);
}
else
{
opacity = Transparent;
ChangeOpacity?.Invoke(opacity);
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.Hide:
if (Global.Vars.SystemTrayMenuSettings.UseFading &&
opacity > StepOut)
{
opacity -= StepOut;
ChangeOpacity?.Invoke(opacity);
}
else if (visible)
{
opacity = 0;
ChangeOpacity?.Invoke(opacity);
visible = false;
Hide?.Invoke();
StartStopTimer(FadingState.Idle);
}
else
{
StartStopTimer(FadingState.Idle);
}
break;
case FadingState.Idle:
default:
StartStopTimer(FadingState.Idle);
break;
}
}
}
}

View File

@@ -0,0 +1,147 @@
// <copyright file="ImagingHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
/// <summary>
/// Provides helper methods for imaging.
/// </summary>
public static class ImagingHelper
{
/// <summary>
/// Converts a PNG image to a icon (ico).
/// </summary>
/// <param name="input">The input stream.</param>
/// <param name="output">The output stream.</param>
/// <param name="size">The size (16x16 px by default).</param>
/// <param name="preserveAspectRatio">Preserve the aspect ratio.</param>
/// <returns>Wether or not the icon was succesfully generated.</returns>
public static bool ConvertToIcon(Stream input, Stream output, int size = 16, bool preserveAspectRatio = false)
{
Bitmap inputBitmap = (Bitmap)Image.FromStream(input);
if (inputBitmap != null)
{
int width, height;
if (preserveAspectRatio)
{
width = size;
height = inputBitmap.Height / inputBitmap.Width * size;
}
else
{
width = height = size;
}
Bitmap newBitmap = new(inputBitmap, new Size(width, height));
if (newBitmap != null)
{
// save the resized png into a memory stream for future use
using MemoryStream memoryStream = new();
newBitmap.Save(memoryStream, ImageFormat.Png);
BinaryWriter iconWriter = new(output);
if (output != null && iconWriter != null)
{
// 0-1 reserved, 0
iconWriter.Write((byte)0);
iconWriter.Write((byte)0);
// 2-3 image type, 1 = icon, 2 = cursor
iconWriter.Write((short)1);
// 4-5 number of images
iconWriter.Write((short)1);
// image entry 1
// 0 image width
iconWriter.Write((byte)width);
// 1 image height
iconWriter.Write((byte)height);
// 2 number of colors
iconWriter.Write((byte)0);
// 3 reserved
iconWriter.Write((byte)0);
// 4-5 color planes
iconWriter.Write((short)0);
// 6-7 bits per pixel
iconWriter.Write((short)32);
// 8-11 size of image data
iconWriter.Write((int)memoryStream.Length);
// 12-15 offset of image data
iconWriter.Write(6 + 16);
// write image data
// png data must contain the whole png data file
iconWriter.Write(memoryStream.ToArray());
iconWriter.Flush();
return true;
}
}
return false;
}
return false;
}
/// <summary>
/// Converts a PNG image to a icon (ico).
/// </summary>
/// <param name="inputPath">The input path.</param>
/// <param name="outputPath">The output path.</param>
/// <param name="size">The size (16x16 px by default).</param>
/// <param name="preserveAspectRatio">Preserve the aspect ratio.</param>
/// <returns>Wether or not the icon was succesfully generated.</returns>
public static bool ConvertToIcon(string inputPath, string outputPath, int size = 16, bool preserveAspectRatio = false)
{
using FileStream inputStream = new(inputPath, FileMode.Open);
using FileStream outputStream = new(outputPath, FileMode.OpenOrCreate);
return ConvertToIcon(inputStream, outputStream, size, preserveAspectRatio);
}
public static Image RotateImage(Image img, float rotationAngle)
{
// create an empty Bitmap image
Bitmap bmp = new(img.Width, img.Height);
// turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
// now we set the rotation point to the center of our image
gfx.TranslateTransform(0.5f + ((float)bmp.Width / 2), 0.5f + ((float)bmp.Height / 2));
// now rotate the image
gfx.RotateTransform(rotationAngle);
gfx.TranslateTransform(0.5f - ((float)bmp.Width / 2), 0.5f - ((float)bmp.Height / 2));
// set the InterpolationMode to HighQualityBicubic so to ensure a high
// quality image once it is transformed to the specified size
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
// now draw our new image onto the graphics object
gfx.DrawImage(img, new Point(0, 0));
// dispose of our Graphics object
gfx.Dispose();
// return the image
return bmp;
}
}
}

View File

@@ -0,0 +1,215 @@
// <copyright file="JoystickHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helpers
{
using System;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection.Metadata;
using System.Threading;
using System.Windows.Forms;
using SharpDX.DirectInput;
public class JoystickHelper : IDisposable
{
private readonly System.Timers.Timer timerReadJoystick = new();
private readonly object lockRead = new();
private Joystick joystick;
private Keys pressingKey;
private int pressingKeyCounter;
private bool joystickHelperEnabled;
public JoystickHelper()
{
timerReadJoystick.Interval = 80;
timerReadJoystick.Elapsed += ReadJoystickLoop;
timerReadJoystick.Enabled = false;
if (Global.Vars.SystemTrayMenuSettings.SupportGamepad)
{
timerReadJoystick.Start();
}
}
~JoystickHelper() // the finalizer
{
Dispose(false);
}
public event Action<Keys> KeyPressed;
public void Enable()
{
joystickHelperEnabled = true;
}
public void Disable()
{
joystickHelperEnabled = false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timerReadJoystick.Elapsed -= ReadJoystickLoop;
timerReadJoystick?.Dispose();
joystick?.Dispose();
}
}
private static Keys ReadKeyFromState(JoystickUpdate state)
{
Keys keys = Keys.None;
switch (state.Offset)
{
case JoystickOffset.PointOfViewControllers0:
switch (state.Value)
{
case 0:
keys = Keys.Up;
break;
case 9000:
keys = Keys.Right;
break;
case 18000:
keys = Keys.Down;
break;
case 27000:
keys = Keys.Left;
break;
default:
break;
}
break;
case JoystickOffset.Buttons0:
if (state.Value == 128)
{
keys = Keys.Enter;
}
break;
default:
break;
}
return keys;
}
private void ReadJoystickLoop(object sender, System.Timers.ElapsedEventArgs e)
{
if (joystickHelperEnabled)
{
lock (lockRead)
{
timerReadJoystick.Stop();
if (joystick == null)
{
Thread.Sleep(3000);
InitializeJoystick();
}
else
{
ReadJoystick();
}
timerReadJoystick.Start();
}
}
}
private void ReadJoystick()
{
try
{
joystick.Poll();
JoystickUpdate[] datas = joystick.GetBufferedData();
foreach (JoystickUpdate state in datas)
{
if (state.Value < 0)
{
pressingKey = Keys.None;
pressingKeyCounter = 0;
continue;
}
Keys key = ReadKeyFromState(state);
if (key != Keys.None)
{
KeyPressed?.Invoke(key);
if (state.Offset == JoystickOffset.PointOfViewControllers0)
{
pressingKeyCounter = 0;
pressingKey = key;
}
}
}
if (pressingKey != Keys.None)
{
pressingKeyCounter += 1;
if (pressingKeyCounter > 1)
{
KeyPressed?.Invoke(pressingKey);
}
}
}
catch
{
joystick?.Dispose();
joystick = null;
}
}
private void InitializeJoystick()
{
// Initialize DirectInput
DirectInput directInput = new();
// Find a Joystick Guid
Guid joystickGuid = Guid.Empty;
foreach (DeviceInstance deviceInstance in directInput.GetDevices(
DeviceType.Gamepad,
DeviceEnumerationFlags.AllDevices))
{
joystickGuid = deviceInstance.InstanceGuid;
}
// If Gamepad not found, look for a Joystick
if (joystickGuid == Guid.Empty)
{
foreach (DeviceInstance deviceInstance in directInput.GetDevices(
DeviceType.Joystick,
DeviceEnumerationFlags.AllDevices))
{
joystickGuid = deviceInstance.InstanceGuid;
}
}
// If Joystick found
if (joystickGuid != Guid.Empty)
{
// Instantiate the joystick
joystick = new Joystick(directInput, joystickGuid);
// Set BufferSize in order to use buffered data.
joystick.Properties.BufferSize = 128;
var handle = Process.GetCurrentProcess().MainWindowHandle;
joystick.SetCooperativeLevel(handle, CooperativeLevel.NonExclusive | CooperativeLevel.Background);
// Acquire the joystick
joystick.Acquire();
}
}
}
}

View File

@@ -0,0 +1,27 @@
// <copyright file="KeyPressedEventArgs.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
/// <summary>
/// Event Args for the event that is fired after the hot key has been pressed.
/// </summary>
internal class KeyPressedEventArgs : EventArgs
{
private readonly Keys key;
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key)
{
Modifier = modifier;
this.key = key;
}
internal KeyboardHookModifierKeys Modifier { get; }
internal Keys Key => key;
}
}

View File

@@ -0,0 +1,167 @@
// <copyright file="KeyboardHook.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using FSI.BT.Tools.Global.DllImports;
using FSI.BT.Tools.Global.UserInterface.HotkeyTextboxControl;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
public enum KeyboardHookModifierKeys : uint
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Win = 8,
}
public sealed class KeyboardHook : IDisposable
{
private readonly Window window = new();
private int currentId;
public KeyboardHook()
{
// register the event of the inner native window.
window.KeyPressed += Window_KeyPressed;
}
/// <summary>
/// A hot key has been pressed.
/// </summary>
internal event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
// unregister all the registered hot keys.
for (int i = currentId; i > 0; i--)
{
NativeMethods.User32UnregisterHotKey(window.Handle, i);
}
// dispose the inner native window.
window.KeyPressed -= Window_KeyPressed;
window.Dispose();
}
/// <summary>
/// Registers a hot key in the system.
/// </summary>
/// <param name="key">The key itself that is associated with the hot key.</param>
internal void RegisterHotKey(Keys key)
{
uint keyModifiersNone = 0;
RegisterHotKey(keyModifiersNone, key);
}
internal void RegisterHotKey()
{
KeyboardHookModifierKeys modifiers = KeyboardHookModifierKeys.None;
string modifiersString = Global.Vars.SystemTrayMenuSettings.HotKey;
if (!string.IsNullOrEmpty(modifiersString))
{
if (modifiersString.ToUpperInvariant().Contains("ALT", StringComparison.InvariantCulture))
{
modifiers |= KeyboardHookModifierKeys.Alt;
}
if (modifiersString.ToUpperInvariant().Contains("CTRL", StringComparison.InvariantCulture) ||
modifiersString.ToUpperInvariant().Contains("STRG", StringComparison.InvariantCulture))
{
modifiers |= KeyboardHookModifierKeys.Control;
}
if (modifiersString.ToUpperInvariant().Contains("SHIFT", StringComparison.InvariantCulture))
{
modifiers |= KeyboardHookModifierKeys.Shift;
}
if (modifiersString.ToUpperInvariant().Contains("WIN", StringComparison.InvariantCulture))
{
modifiers |= KeyboardHookModifierKeys.Win;
}
}
RegisterHotKey(
modifiers,
HotkeyControl.HotkeyFromString(
Global.Vars.SystemTrayMenuSettings.HotKey));
}
/// <summary>
/// Registers a hot key in the system.
/// </summary>
/// <param name="modifier">The modifiers that are associated with the hot key.</param>
/// <param name="key">The key itself that is associated with the hot key.</param>
internal void RegisterHotKey(KeyboardHookModifierKeys modifier, Keys key)
{
RegisterHotKey((uint)modifier, key);
}
private void Window_KeyPressed(object sender, KeyPressedEventArgs e)
{
KeyPressed?.Invoke(this, e);
}
private void RegisterHotKey(uint modifier, Keys key)
{
currentId += 1;
if (!NativeMethods.User32RegisterHotKey(
window.Handle, currentId, modifier, (uint)key))
{
throw new InvalidOperationException(
Global.Utilities.Translator.GetText("Could not register the hot key."));
}
}
/// <summary>
/// Represents the window that is used internally to get the messages.
/// </summary>
private class Window : NativeWindow, IDisposable
{
private const int WmHotkey = 0x0312;
public Window()
{
// create the handle for the window.
CreateHandle(new CreateParams());
}
public event EventHandler<KeyPressedEventArgs> KeyPressed;
public void Dispose()
{
DestroyHandle();
}
/// <summary>
/// Overridden to get the notifications.
/// </summary>
/// <param name="m">m.</param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// check if we got a hot key pressed.
if (m.Msg == WmHotkey)
{
// get the keys.
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF);
// invoke the event to notify the parent.
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
}
}
}
}
}

View File

@@ -0,0 +1,252 @@
//// <copyright file="GitHubUpdate.cs" company="PlaceholderCompany">
//// Copyright (c) PlaceholderCompany. All rights reserved.
//// </copyright>
//namespace FSI.BT.Tools.SystemTrayMenu.Helper.Updater
//{
// using System;
// using System.Collections.Generic;
// using System.Drawing;
// using System.Net.Http;
// using System.Reflection;
// using System.Windows.Forms;
// using FSI.BT.Tools.Global.Utilities;
// using FSI.BT.Tools.SystemTrayMenu.Utilities;
// public class GitHubUpdate
// {
// private static List<Dictionary<string, object>> releases;
// private static Form newVersionForm;
// public static void ActivateNewVersionFormOrCheckForUpdates(bool showWhenUpToDate)
// {
// if (newVersionForm != null)
// {
// newVersionForm.HandleInvoke(newVersionForm.Activate);
// }
// else
// {
// CheckForUpdates(showWhenUpToDate);
// }
// }
// private static void CheckForUpdates(bool showWhenUpToDate)
// {
// string urlGithubReleases = @"http://api.github.com/repos/Hofknecht/SystemTrayMenu/releases";
// HttpClient client = new();
// // https://developer.github.com/v3/#user-agent-required
// client.DefaultRequestHeaders.Add("User-Agent", "FSI.BT.Tools.SystemTrayMenu/" + Application.ProductVersion.ToString());
// // https://developer.github.com/v3/media/#request-specific-version
// client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3.text+json");
// try
// {
// using HttpResponseMessage response = client.GetAsync(urlGithubReleases).Result;
// using HttpContent content = response.Content;
// string responseString = content.ReadAsStringAsync().Result;
// releases = responseString.FromJson<List<Dictionary<string, object>>>();
// }
// catch (Exception ex)
// {
// Log.Warn($"{nameof(CheckForUpdates)} failed", ex);
// }
// if (releases == null)
// {
// Log.Info($"{nameof(CheckForUpdates)} failed.");
// }
// else
// {
// RemoveCurrentAndOlderVersions();
// ShowNewVersionOrUpToDateDialog(showWhenUpToDate);
// }
// newVersionForm?.Dispose();
// newVersionForm = null;
// }
// private static void RemoveCurrentAndOlderVersions()
// {
// int releasesCount = releases.Count;
// Version versionCurrent = Assembly.GetExecutingAssembly().GetName().Version;
// for (int i = 0; i < releasesCount; i++)
// {
// string tagName = releases[i]["tag_name"].ToString();
// Version versionGitHub = new(tagName.Replace("v", string.Empty));
// if (versionGitHub.CompareTo(versionCurrent) < 1)
// {
// releases.RemoveRange(i, releasesCount - i);
// break;
// }
// }
// }
// private static void ShowNewVersionOrUpToDateDialog(bool showWhenUpToDate)
// {
// if (releases.Count > 0)
// {
// if (NewVersionDialog() == DialogResult.Yes)
// {
// Log.ProcessStart("https://github.com/Hofknecht/SystemTrayMenu/releases");
// }
// }
// else if (showWhenUpToDate)
// {
// MessageBox.Show(Global.Utilities.Translator.GetText("You have the latest version of SystemTrayMenu!"));
// }
// }
// /// <summary>
// /// Creates a window to show changelog of new available versions.
// /// </summary>
// /// <param name="LatestVersionTitle">Name of latest release.</param>
// /// <param name="Changelog">Pathnotes.</param>
// /// <returns>OK = OK, Yes = Website, else = Cancel.</returns>
// private static DialogResult NewVersionDialog()
// {
// const int ClientPad = 15;
// newVersionForm = new()
// {
// StartPosition = FormStartPosition.CenterScreen,
// FormBorderStyle = FormBorderStyle.FixedDialog,
// Icon = Config.GetAppIcon(),
// ShowInTaskbar = false,
// };
// newVersionForm.FormBorderStyle = FormBorderStyle.Sizable;
// newVersionForm.MaximizeBox = true;
// newVersionForm.MinimizeBox = false;
// newVersionForm.ClientSize = new Size(600, 400);
// newVersionForm.MinimumSize = newVersionForm.ClientSize;
// newVersionForm.Text = Global.Utilities.Translator.GetText("New version available!");
// Label label = new()
// {
// Size = new Size(newVersionForm.ClientSize.Width - ClientPad, 20),
// Location = new Point(ClientPad, ClientPad),
// Text = $"{Global.Utilities.Translator.GetText("Latest available version:")} {GetLatestVersionName()}",
// };
// newVersionForm.Controls.Add(label);
// Button buttonOK = new()
// {
// DialogResult = DialogResult.OK,
// Name = "buttonOK",
// };
// buttonOK.Location = new Point(
// newVersionForm.ClientSize.Width - buttonOK.Size.Width - ClientPad,
// newVersionForm.ClientSize.Height - buttonOK.Size.Height - ClientPad);
// buttonOK.MinimumSize = new Size(75, 23);
// buttonOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
// buttonOK.Text = Global.Utilities.Translator.GetText("OK");
// buttonOK.AutoSizeMode = AutoSizeMode.GrowAndShrink;
// buttonOK.AutoSize = true;
// newVersionForm.Controls.Add(buttonOK);
// Button buttonGoToDownloadPage = new()
// {
// DialogResult = DialogResult.Yes,
// Name = "buttonGoToDownloadPage",
// };
// buttonGoToDownloadPage.Location = new Point(
// newVersionForm.ClientSize.Width - buttonGoToDownloadPage.Size.Width - ClientPad - buttonOK.Size.Width - ClientPad,
// newVersionForm.ClientSize.Height - buttonGoToDownloadPage.Size.Height - ClientPad);
// buttonGoToDownloadPage.MinimumSize = new Size(75, 23);
// buttonGoToDownloadPage.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
// buttonGoToDownloadPage.Text = Global.Utilities.Translator.GetText("Go to download page");
// buttonGoToDownloadPage.AutoSizeMode = AutoSizeMode.GrowAndShrink;
// buttonGoToDownloadPage.AutoSize = true;
// newVersionForm.Controls.Add(buttonGoToDownloadPage);
// TextBox textBox = new()
// {
// Location = new Point(ClientPad, label.Location.Y + label.Size.Height + 5),
// };
// textBox.Size = new Size(
// newVersionForm.ClientSize.Width - (ClientPad * 2),
// buttonOK.Location.Y - ClientPad - textBox.Location.Y);
// textBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
// textBox.Multiline = true;
// textBox.Text = GetChangelog();
// textBox.ReadOnly = true;
// textBox.ScrollBars = ScrollBars.Both;
// textBox.BackColor = Color.FromKnownColor(KnownColor.Window);
// textBox.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
// newVersionForm.Controls.Add(textBox);
// newVersionForm.AcceptButton = buttonOK;
// return newVersionForm.ShowDialog();
// }
// /// <summary>
// /// Returns the latest release version name.
// /// </summary>
// /// <returns>Version name.</returns>
// private static string GetLatestVersionName()
// {
// string result = "Unknown";
// if (releases == null)
// {
// return result;
// }
// try
// {
// result = releases[0]["tag_name"].ToString().Replace("v", string.Empty);
// }
// catch (Exception ex)
// {
// Log.Warn($"{nameof(GetLatestVersionName)} failed", ex);
// }
// return result;
// }
// /// <summary>
// /// Returns the change log from current version up to the latest release version.
// /// </summary>
// /// <returns>Change log summary or error text.</returns>
// private static string GetChangelog()
// {
// string result = string.Empty;
// string errorstr = "An error occurred during update check!" + Environment.NewLine;
// if (releases == null)
// {
// return errorstr + "Could not receive changelog!";
// }
// try
// {
// for (int i = 0; i < releases.Count; i++)
// {
// Dictionary<string, object> release = releases[i];
// result += release["name"].ToString()
// + Environment.NewLine
// + release["body_text"].ToString()
// .Replace("\n\n", Environment.NewLine)
// .Replace("\n \n", Environment.NewLine)
// + Environment.NewLine + Environment.NewLine;
// if (i < releases.Count)
// {
// result += "--------------------------------------------------" +
// "-------------------------------------------------------"
// + Environment.NewLine;
// }
// }
// result = result.Replace("\n", Environment.NewLine);
// }
// catch (Exception ex)
// {
// Log.Warn($"{nameof(GetChangelog)}", ex);
// result = errorstr + ex.Message.ToString();
// }
// return result;
// }
// }
//}

View File

@@ -0,0 +1,480 @@
// <copyright file="JsonParser.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper.Updater
{
// Copyright (c) 2018 Alex Parker
// Copyright (c) 2018-2019 Peter Kirmeier
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
// Really simple JSON parser in ~300 lines
// - Attempts to parse JSON files with minimal GC allocation
// - Nice and simple "[1,2,3]".FromJson<List<int>>() API
// - Classes and structs can be parsed too!
// class Foo { public int Value; }
// "{\"Value\":10}".FromJson<Foo>()
// - Can parse JSON without type information into Dictionary<string,object> and List<object> e.g.
// "[1,2,3]".FromJson<object>().GetType() == typeof(List<object>)
// "{\"Value\":10}".FromJson<object>().GetType() == typeof(Dictionary<string,object>)
// - No JIT Emit support to support AOT compilation on iOS
// - Attempts are made to NOT throw an exception if the JSON is corrupted or invalid: returns null instead.
// - Only public fields and property setters on classes/structs will be written to
//
// Limitations:
// - No JIT Emit support to parse structures quickly
// - Limited to parsing <2GB JSON files (due to int.MaxValue)
// - Parsing of abstract classes or interfaces is NOT supported and will throw an exception.
public static class JSONParser
{
[ThreadStatic]
private static Stack<List<string>> splitArrayPool;
[ThreadStatic]
private static StringBuilder stringBuilder;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, FieldInfo>> fieldInfoCache;
[ThreadStatic]
private static Dictionary<Type, Dictionary<string, PropertyInfo>> propertyInfoCache;
public static T FromJson<T>(this string json)
{
// Initialize, if needed, the ThreadStatic variables
propertyInfoCache ??= new Dictionary<Type, Dictionary<string, PropertyInfo>>();
fieldInfoCache ??= new Dictionary<Type, Dictionary<string, FieldInfo>>();
stringBuilder ??= new StringBuilder();
splitArrayPool ??= new Stack<List<string>>();
// Remove all whitespace not within strings to make parsing simpler
stringBuilder.Length = 0;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
if (c == '"')
{
i = AppendUntilStringEnd(true, i, json);
continue;
}
if (char.IsWhiteSpace(c))
{
continue;
}
stringBuilder.Append(c);
}
// Parse the thing!
return (T)ParseValue(typeof(T), stringBuilder.ToString());
}
internal static object ParseValue(Type type, string json)
{
if (type == typeof(string))
{
if (json.Length <= 2)
{
return string.Empty;
}
StringBuilder parseStringBuilder = new(json.Length);
for (int i = 1; i < json.Length - 1; ++i)
{
if (json[i] == '\\' && i + 1 < json.Length - 1)
{
int j = "\"\\nrtbf/".IndexOf(json[i + 1]);
if (j >= 0)
{
parseStringBuilder.Append("\"\\\n\r\t\b\f/"[j]);
++i;
continue;
}
if (json[i + 1] == 'u' && i + 5 < json.Length - 1)
{
if (uint.TryParse(json.AsSpan(i + 2, 4), System.Globalization.NumberStyles.AllowHexSpecifier, null, out uint c))
{
parseStringBuilder.Append((char)c);
i += 5;
continue;
}
}
}
parseStringBuilder.Append(json[i]);
}
return parseStringBuilder.ToString();
}
if (type.IsPrimitive)
{
var result = Convert.ChangeType(json, type, System.Globalization.CultureInfo.InvariantCulture);
return result;
}
if (type == typeof(decimal))
{
decimal.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out decimal result);
return result;
}
if (json == "null")
{
return null;
}
if (type.IsEnum)
{
if (json[0] == '"')
{
json = json[1..^1];
}
try
{
return Enum.Parse(type, json, false);
}
catch
{
return 0;
}
}
if (type.IsArray)
{
Type arrayType = type.GetElementType();
if (json[0] != '[' || json[^1] != ']')
{
return null;
}
List<string> elems = Split(json);
Array newArray = Array.CreateInstance(arrayType, elems.Count);
for (int i = 0; i < elems.Count; i++)
{
newArray.SetValue(ParseValue(arrayType, elems[i]), i);
}
splitArrayPool.Push(elems);
return newArray;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
{
Type listType = type.GetGenericArguments()[0];
if (json[0] != '[' || json[^1] != ']')
{
return null;
}
List<string> elems = Split(json);
var list = (IList)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count });
for (int i = 0; i < elems.Count; i++)
{
list.Add(ParseValue(listType, elems[i]));
}
splitArrayPool.Push(elems);
return list;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>))
{
Type keyType, valueType;
{
Type[] args = type.GetGenericArguments();
keyType = args[0];
valueType = args[1];
}
// Refuse to parse dictionary keys that aren't of type string
if (keyType != typeof(string))
{
return null;
}
// Must be a valid dictionary element
if (json[0] != '{' || json[^1] != '}')
{
return null;
}
// The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return null;
}
var dictionary = (IDictionary)type.GetConstructor(new Type[] { typeof(int) }).Invoke(new object[] { elems.Count / 2 });
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
{
continue;
}
string keyValue = elems[i][1..^1];
object val = ParseValue(valueType, elems[i + 1]);
dictionary.Add(keyValue, val);
}
return dictionary;
}
if (type == typeof(object))
{
return ParseAnonymousValue(json);
}
if (json[0] == '{' && json[^1] == '}')
{
return ParseObject(type, json);
}
return null;
}
private static int AppendUntilStringEnd(bool appendEscapeCharacter, int startIdx, string json)
{
stringBuilder.Append(json[startIdx]);
for (int i = startIdx + 1; i < json.Length; i++)
{
if (json[i] == '\\')
{
if (appendEscapeCharacter)
{
stringBuilder.Append(json[i]);
}
stringBuilder.Append(json[i + 1]);
i++; // Skip next character as it is escaped
}
else if (json[i] == '"')
{
stringBuilder.Append(json[i]);
return i;
}
else
{
stringBuilder.Append(json[i]);
}
}
return json.Length - 1;
}
// Splits { <value>:<value>, <value>:<value> } and [ <value>, <value> ] into a list of <value> strings
private static List<string> Split(string json)
{
List<string> splitArray = splitArrayPool.Count > 0 ? splitArrayPool.Pop() : new List<string>();
splitArray.Clear();
if (json.Length == 2)
{
return splitArray;
}
int parseDepth = 0;
stringBuilder.Length = 0;
for (int i = 1; i < json.Length - 1; i++)
{
switch (json[i])
{
case '[':
case '{':
parseDepth++;
break;
case ']':
case '}':
parseDepth--;
break;
case '"':
i = AppendUntilStringEnd(true, i, json);
continue;
case ',':
case ':':
if (parseDepth == 0)
{
splitArray.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
continue;
}
break;
}
stringBuilder.Append(json[i]);
}
splitArray.Add(stringBuilder.ToString());
return splitArray;
}
private static object ParseAnonymousValue(string json)
{
if (json.Length == 0)
{
return null;
}
if (json[0] == '{' && json[^1] == '}')
{
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return null;
}
var dict = new Dictionary<string, object>(elems.Count / 2);
for (int i = 0; i < elems.Count; i += 2)
{
dict.Add(elems[i][1..^1], ParseAnonymousValue(elems[i + 1]));
}
return dict;
}
if (json[0] == '[' && json[^1] == ']')
{
List<string> items = Split(json);
var finalList = new List<object>(items.Count);
for (int i = 0; i < items.Count; i++)
{
finalList.Add(ParseAnonymousValue(items[i]));
}
return finalList;
}
if (json[0] == '"' && json[^1] == '"')
{
return ParseValue(typeof(string), json); // fix https://github.com/zanders3/json/issues/29
}
if (char.IsDigit(json[0]) || json[0] == '-')
{
if (json.Contains('.'))
{
double.TryParse(json, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double result);
return result;
}
else
{
_ = int.TryParse(json, out int result);
return result;
}
}
if (json == "true")
{
return true;
}
if (json == "false")
{
return false;
}
// handles json == "null" as well as invalid JSON
return null;
}
private static Dictionary<string, T> CreateMemberNameDictionary<T>(T[] members)
where T : MemberInfo
{
Dictionary<string, T> nameToMember = new(StringComparer.OrdinalIgnoreCase);
for (int i = 0; i < members.Length; i++)
{
/*T member = members[i];
if (member.IsDefined(typeof(IgnoreDataMemberAttribute), true))
continue;
string name = member.Name;
if (member.IsDefined(typeof(DataMemberAttribute), true))
{
DataMemberAttribute dataMemberAttribute = (DataMemberAttribute)Attribute.GetCustomAttribute(member, typeof(DataMemberAttribute), true);
if (!string.IsNullOrEmpty(dataMemberAttribute.Name))
name = dataMemberAttribute.Name;
}
nameToMember.Add(name, member);*/
// The above code is not working with .Net framework 2.0, so we ignore these attributes for compatibility reasons:
nameToMember.Add(members[i].Name, members[i]);
}
return nameToMember;
}
private static object ParseObject(Type type, string json)
{
object instance = FormatterServices.GetUninitializedObject(type);
// The list is split into key/value pairs only, this means the split must be divisible by 2 to be valid JSON
List<string> elems = Split(json);
if (elems.Count % 2 != 0)
{
return instance;
}
if (!fieldInfoCache.TryGetValue(type, out Dictionary<string, FieldInfo> nameToField))
{
nameToField = CreateMemberNameDictionary(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
fieldInfoCache.Add(type, nameToField);
}
if (!propertyInfoCache.TryGetValue(type, out Dictionary<string, PropertyInfo> nameToProperty))
{
nameToProperty = CreateMemberNameDictionary(type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy));
propertyInfoCache.Add(type, nameToProperty);
}
for (int i = 0; i < elems.Count; i += 2)
{
if (elems[i].Length <= 2)
{
continue;
}
string key = elems[i][1..^1];
string value = elems[i + 1];
if (nameToField.TryGetValue(key, out FieldInfo fieldInfo))
{
fieldInfo.SetValue(instance, ParseValue(fieldInfo.FieldType, value));
}
else if (nameToProperty.TryGetValue(key, out PropertyInfo propertyInfo))
{
propertyInfo.SetValue(instance, ParseValue(propertyInfo.PropertyType, value), null);
}
}
return instance;
}
}
}

View File

@@ -0,0 +1,16 @@
// <copyright file="WindowsExplorerSort.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System.Collections.Generic;
internal class WindowsExplorerSort : IComparer<string>
{
public int Compare(string x, string y)
{
return Global.DllImports.NativeMethods.ShlwapiStrCmpLogicalW(x, y);
}
}
}

View File

@@ -0,0 +1,80 @@
// <copyright file="WindowsTaskbar.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using static Global.DllImports.NativeMethods;
public enum TaskbarPosition
{
Unknown = -1,
Left,
Top,
Right,
Bottom,
}
public sealed class WindowsTaskbar
{
private const string ClassName = "Shell_TrayWnd";
public WindowsTaskbar()
{
IntPtr taskbarHandle = User32FindWindow(ClassName, null);
APPBARDATA data = new()
{
cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)),
hWnd = taskbarHandle,
};
IntPtr result = Shell32SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
{
Bounds = new Rectangle(20, 20, 20, 20);
}
else
{
Position = (TaskbarPosition)data.uEdge;
Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);
data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA));
result = Shell32SHAppBarMessage(ABM.GetState, ref data);
int state = result.ToInt32();
AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
}
public Rectangle Bounds
{
get;
private set;
}
public TaskbarPosition Position
{
get;
private set;
}
public Point Location => Bounds.Location;
public Size Size => Bounds.Size;
public bool AlwaysOnTop
{
get;
private set;
}
public bool AutoHide
{
get;
private set;
}
}
}

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="49543SystemTrayMenu.SystemTrayMenu"
Publisher="CN=5884501C-92ED-45DE-9508-9D987C314243"
Version="3.0.0.0" />
<Properties>
<DisplayName>SystemTrayMenu</DisplayName>
<PublisherDisplayName>SystemTrayMenu</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="SystemTrayMenu"
Description="Packaging"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png"/>
<uap:SplashScreen Image="Images\SplashScreen.png" />
<uap:LockScreen BadgeLogo="Images\BadgeLogo.png" Notification="badge"/>
</uap:VisualElements>
<Extensions>
<uap5:Extension
Category="windows.startupTask">
<uap5:StartupTask
TaskId="MyStartupId"
Enabled="false"
DisplayName="SystemTrayMenu" />
</uap5:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View File

@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleasePackage|AnyCPU">
<Configuration>ReleasePackage</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleasePackage|x64">
<Configuration>ReleasePackage</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleasePackage|x86">
<Configuration>ReleasePackage</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>01d77f37-786a-4dc4-a1ad-bc1eec54eae3</ProjectGuid>
<TargetPlatformVersion>10.0.22000.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<EntryPointProjectUniqueName>..\SystemTrayMenu.csproj</EntryPointProjectUniqueName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x86|x64</AppxBundlePlatforms>
<AppInstallerUri>https://github.com/Hofknecht/SystemTrayMenu/releases</AppInstallerUri>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<AppxSymbolPackageEnabled>True</AppxSymbolPackageEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<None Include="Package.StoreAssociation.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SystemTrayMenu.csproj">
<SkipGetTargetFrameworkProperties>True</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Content Include="Images\BadgeLogo.scale-100.png" />
<Content Include="Images\BadgeLogo.scale-125.png" />
<Content Include="Images\BadgeLogo.scale-150.png" />
<Content Include="Images\BadgeLogo.scale-200.png" />
<Content Include="Images\BadgeLogo.scale-400.png" />
<Content Include="Images\LargeTile.scale-100.png" />
<Content Include="Images\LargeTile.scale-125.png" />
<Content Include="Images\LargeTile.scale-150.png" />
<Content Include="Images\LargeTile.scale-200.png" />
<Content Include="Images\LargeTile.scale-400.png" />
<Content Include="Images\SmallTile.scale-100.png" />
<Content Include="Images\SmallTile.scale-125.png" />
<Content Include="Images\SmallTile.scale-150.png" />
<Content Include="Images\SmallTile.scale-200.png" />
<Content Include="Images\SmallTile.scale-400.png" />
<Content Include="Images\SplashScreen.scale-100.png" />
<Content Include="Images\SplashScreen.scale-125.png" />
<Content Include="Images\SplashScreen.scale-150.png" />
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\SplashScreen.scale-400.png" />
<Content Include="Images\Square150x150Logo.scale-100.png" />
<Content Include="Images\Square150x150Logo.scale-125.png" />
<Content Include="Images\Square150x150Logo.scale-150.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-400.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-24.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-32.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-48.png" />
<Content Include="Images\Square44x44Logo.scale-100.png" />
<Content Include="Images\Square44x44Logo.scale-125.png" />
<Content Include="Images\Square44x44Logo.scale-150.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-400.png" />
<Content Include="Images\Square44x44Logo.targetsize-16.png" />
<Content Include="Images\Square44x44Logo.targetsize-24.png" />
<Content Include="Images\Square44x44Logo.targetsize-256.png" />
<Content Include="Images\Square44x44Logo.targetsize-32.png" />
<Content Include="Images\Square44x44Logo.targetsize-48.png" />
<Content Include="Images\StoreLogo.scale-100.png" />
<Content Include="Images\StoreLogo.scale-125.png" />
<Content Include="Images\StoreLogo.scale-150.png" />
<Content Include="Images\StoreLogo.scale-200.png" />
<Content Include="Images\StoreLogo.scale-400.png" />
<Content Include="Images\Wide310x150Logo.scale-100.png" />
<Content Include="Images\Wide310x150Logo.scale-125.png" />
<Content Include="Images\Wide310x150Logo.scale-150.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
<Content Include="Images\Wide310x150Logo.scale-400.png" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
</Project>

View File

@@ -0,0 +1,349 @@
// <copyright file="CustomSettingsProvider.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Properties
{
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
internal class CustomSettingsProvider : SettingsProvider
{
private const string NameOf = "name";
private const string SerializeAs = "serializeAs";
private const string Config = "configuration";
private const string UserSettings = "userSettings";
private const string Setting = "setting";
private bool loaded;
/// <summary>
/// Initializes a new instance of the <see cref="CustomSettingsProvider"/> class.
/// Loads the file into memory.
/// </summary>
public CustomSettingsProvider()
{
SettingsDictionary = new Dictionary<string, SettingStruct>();
}
/// <summary>
/// Gets the setting key this is returning must set before the settings are used.
/// e.g. <c>Properties.Settings.Default.SettingsKey = @"C:\temp\user.config";</c>.
/// </summary>
public static string UserConfigPath => Path.Combine(
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
$"FSI.BT.Tools.SystemTrayMenu"),
$"user-{Environment.MachineName}.config");
public static string ConfigPathAssembly => Path.Combine(
Directory.GetParent(Assembly.GetEntryAssembly().Location).FullName,
$"user.config");
/// <summary>
/// Gets or sets override.
/// </summary>
public override string ApplicationName
{
get => Assembly.GetExecutingAssembly().ManifestModule.Name;
set
{
// do nothing
}
}
/// <summary>
/// Gets or sets in memory storage of the settings values.
/// </summary>
private Dictionary<string, SettingStruct> SettingsDictionary { get; set; }
public static bool IsActivatedConfigPathAssembly()
{
return IsConfigPathAssembly();
}
public static void ActivateConfigPathAssembly()
{
CreateEmptyConfigIfNotExists(ConfigPathAssembly);
}
public static void DeactivateConfigPathAssembly()
{
if (IsConfigPathAssembly())
{
try
{
File.Delete(ConfigPathAssembly);
}
catch (Exception ex)
{
Log.Warn($"Could not delete {ConfigPathAssembly}", ex);
}
}
}
/// <summary>
/// Override.
/// </summary>
/// <param name="name">name.</param>
/// <param name="config">config.</param>
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(ApplicationName, config);
}
/// <summary>
/// Must override this, this is the bit that matches up the designer properties to the dictionary values.
/// </summary>
/// <param name="context">context.</param>
/// <param name="collection">collection.</param>
/// <returns>SettingsPropertyValueCollection.</returns>
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
{
// load the file
if (!loaded)
{
loaded = true;
LoadValuesFromFile();
}
// collection that will be returned.
SettingsPropertyValueCollection values = new();
// itterate thought the properties we get from the designer, checking to see if the setting is in the dictionary
foreach (SettingsProperty setting in collection)
{
SettingsPropertyValue value = new(setting)
{
IsDirty = false,
};
// need the type of the value for the strong typing
Type t = Type.GetType(setting.PropertyType.FullName);
if (SettingsDictionary.ContainsKey(setting.Name))
{
value.SerializedValue = SettingsDictionary[setting.Name].Value;
value.PropertyValue = Convert.ChangeType(SettingsDictionary[setting.Name].Value, t, CultureInfo.InvariantCulture);
}
else
{
// use defaults in the case where there are no settings yet
value.SerializedValue = setting.DefaultValue;
value.PropertyValue = Convert.ChangeType(setting.DefaultValue, t, CultureInfo.InvariantCulture);
}
values.Add(value);
}
return values;
}
/// <summary>
/// Must override this, this is the bit that does the saving to file. Called when Settings.Save() is called.
/// </summary>
/// <param name="context">context.</param>
/// <param name="collection">collection.</param>
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
{
// grab the values from the collection parameter and update the values in our dictionary.
foreach (SettingsPropertyValue value in collection)
{
SettingStruct setting = new()
{
Value = value.PropertyValue == null ? string.Empty : value.PropertyValue.ToString(),
Name = value.Name,
SerializeAs = value.Property.SerializeAs.ToString(),
};
if (!SettingsDictionary.ContainsKey(value.Name))
{
SettingsDictionary.Add(value.Name, setting);
}
else
{
SettingsDictionary[value.Name] = setting;
}
}
// now that our local dictionary is up-to-date, save it to disk.
SaveValuesToFile();
}
/// <summary>
/// Creates an empty user.config file...looks like the one MS creates.
/// This could be overkill a simple key/value pairing would probably do.
/// </summary>
private static void CreateEmptyConfigIfNotExists(string path)
{
if (!File.Exists(path))
{
// if the config file is not where it's supposed to be create a new one.
XDocument doc = new();
XDeclaration declaration = new("1.0", "utf-8", "true");
XElement config = new(Config);
XElement userSettings = new(UserSettings);
//XElement group = new(typeof(Settings).FullName);
//userSettings.Add(group);
config.Add(userSettings);
doc.Add(config);
doc.Declaration = declaration;
try
{
doc.Save(path);
}
catch (Exception ex)
{
Log.Warn($"Failed to store config at assembly location {path}", ex);
}
}
}
private static bool IsConfigPathAssembly()
{
bool isconfigPathAssembly = false;
try
{
isconfigPathAssembly = File.Exists(ConfigPathAssembly);
}
catch (Exception ex)
{
Log.Warn("IsConfigPathAssembly failed", ex);
}
return isconfigPathAssembly;
}
private static XDocument LoadOrGetNew(string path)
{
XDocument xDocument = null;
try
{
xDocument = XDocument.Load(path);
}
catch (Exception exceptionWarning)
{
Log.Warn($"Could not load {path}", exceptionWarning);
try
{
File.Delete(path);
CreateEmptyConfigIfNotExists(path);
xDocument = XDocument.Load(path);
}
catch (Exception exceptionError)
{
Log.Error($"Could not delete and create {path}", exceptionError);
}
}
return xDocument;
}
/// <summary>
/// Loads the values of the file into memory.
/// </summary>
private void LoadValuesFromFile()
{
CreateEmptyConfigIfNotExists(UserConfigPath);
// load the xml
XDocument configXml;
if (IsConfigPathAssembly())
{
configXml = LoadOrGetNew(ConfigPathAssembly);
}
else
{
configXml = LoadOrGetNew(UserConfigPath);
}
if (configXml != null)
{
// get all of the <setting name="..." serializeAs="..."> elements.
//IEnumerable<XElement> settingElements = configXml.Element(Config).Element(UserSettings).Element(typeof(Settings).FullName).Elements(Setting);
// iterate through, adding them to the dictionary, (checking for nulls, xml no likey nulls)
// using "String" as default serializeAs...just in case, no real good reason.
//foreach (XElement element in settingElements)
//{
// SettingStruct newSetting = new()
// {
// Name = element.Attribute(NameOf) == null ? string.Empty : element.Attribute(NameOf).Value,
// SerializeAs = element.Attribute(SerializeAs) == null ? "String" : element.Attribute(SerializeAs).Value,
// Value = element.Value ?? string.Empty,
// };
// SettingsDictionary.Add(element.Attribute(NameOf).Value, newSetting);
//}
}
}
/// <summary>
/// Saves the in memory dictionary to the user config file.
/// </summary>
private void SaveValuesToFile()
{
// load the current xml from the file.
XDocument configXml;
if (IsConfigPathAssembly())
{
configXml = LoadOrGetNew(ConfigPathAssembly);
}
else
{
configXml = LoadOrGetNew(UserConfigPath);
}
if (configXml != null)
{
// get the settings group (e.g. <Company.Project.Desktop.Settings>)
//XElement settingsSection = configXml.Element(Config).Element(UserSettings).Element(typeof(Settings).FullName);
// iterate though the dictionary, either updating the value or adding the new setting.
//foreach (KeyValuePair<string, SettingStruct> entry in SettingsDictionary)
//{
// XElement setting = settingsSection.Elements().FirstOrDefault(e => e.Attribute(NameOf).Value == entry.Key);
// if (setting == null)
// {
// // this can happen if a new setting is added via the .settings designer.
// XElement newSetting = new(Setting);
// newSetting.Add(new XAttribute(NameOf, entry.Value.Name));
// newSetting.Add(new XAttribute(SerializeAs, entry.Value.SerializeAs));
// newSetting.Value = entry.Value.Value ?? string.Empty;
// settingsSection.Add(newSetting);
// }
// else
// {
// // update the value if it exists.
// setting.Value = entry.Value.Value ?? string.Empty;
// }
//}
if (IsConfigPathAssembly())
{
configXml.Save(ConfigPathAssembly);
}
configXml.Save(UserConfigPath);
}
}
/// <summary>
/// Helper struct.
/// </summary>
internal struct SettingStruct
{
internal string Name;
internal string SerializeAs;
internal string Value;
}
}
}

View File

@@ -0,0 +1,173 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace FSI.BT.Tools.SystemTrayMenu.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FSI.BT.Tools.SystemTrayMenu.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_arrow_sync_24_regular {
get {
object obj = ResourceManager.GetObject("ic_fluent_arrow_sync_24_regular", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_folder_arrow_right_48_regular {
get {
object obj = ResourceManager.GetObject("ic_fluent_folder_arrow_right_48_regular", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_pin_48_filled {
get {
object obj = ResourceManager.GetObject("ic_fluent_pin_48_filled", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_pin_48_regular {
get {
object obj = ResourceManager.GetObject("ic_fluent_pin_48_regular", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_search_48_regular {
get {
object obj = ResourceManager.GetObject("ic_fluent_search_48_regular", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
public static byte[] ic_fluent_settings_28_regular {
get {
object obj = ResourceManager.GetObject("ic_fluent_settings_28_regular", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon LinkArrow {
get {
object obj = ResourceManager.GetObject("LinkArrow", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon Loading {
get {
object obj = ResourceManager.GetObject("Loading", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon NotFound {
get {
object obj = ResourceManager.GetObject("NotFound", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon SystemTrayMenu {
get {
object obj = ResourceManager.GetObject("FSI.BT.Tools.SystemTrayMenu", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
public static System.Drawing.Icon White50Percentage {
get {
object obj = ResourceManager.GetObject("White50Percentage", resourceCulture);
return ((System.Drawing.Icon)(obj));
}
}
}
}

View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="White50Percentage" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\White50Percentage.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ic_fluent_pin_48_filled" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_pin_48_filled.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ic_fluent_pin_48_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_pin_48_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ic_fluent_search_48_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_search_48_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ic_fluent_folder_arrow_right_48_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_folder_arrow_right_48_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="NotFound" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NotFound.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Loading" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Loading.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ic_fluent_arrow_sync_24_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_arrow_sync_24_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ic_fluent_settings_28_regular" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ic_fluent_settings_28_regular.svg;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="LinkArrow" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\LinkArrow.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="FSI.BT.Tools.SystemTrayMenu" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\..\Global\Icons\FondiumU.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,13 @@
// <copyright file="StaticResources.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Resources
{
using System.Drawing;
public class StaticResources
{
public static readonly Icon LoadingIcon = Properties.Resources.Loading;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M16.2506 5.18011C15.9994 5.50947 16.0627 5.9801 16.3921 6.23128C18.1804 7.59515 19.25 9.70821 19.25 12C19.25 15.736 16.4242 18.812 12.7933 19.2071L13.4697 18.5303C13.7626 18.2374 13.7626 17.7626 13.4697 17.4697C13.2034 17.2034 12.7867 17.1792 12.4931 17.3971L12.409 17.4697L10.409 19.4697C10.1427 19.7359 10.1185 20.1526 10.3364 20.4462L10.409 20.5303L12.409 22.5303C12.7019 22.8232 13.1768 22.8232 13.4697 22.5303C13.7359 22.2641 13.7601 21.8474 13.5423 21.5538L13.4697 21.4697L12.7194 20.7208C17.2154 20.355 20.75 16.5903 20.75 12C20.75 9.23526 19.4582 6.68321 17.3017 5.03856C16.9724 4.78738 16.5017 4.85075 16.2506 5.18011ZM10.5303 1.46967C10.2374 1.76256 10.2374 2.23744 10.5303 2.53033L11.2796 3.27923C6.78409 3.6456 3.25 7.41008 3.25 12C3.25 14.6445 4.43126 17.0974 6.43081 18.7491C6.75016 19.0129 7.22289 18.9679 7.48669 18.6485C7.75048 18.3292 7.70545 17.8564 7.3861 17.5926C5.72793 16.2229 4.75 14.1922 4.75 12C4.75 8.26436 7.57532 5.18861 11.2057 4.79301L10.5303 5.46967C10.2374 5.76256 10.2374 6.23744 10.5303 6.53033C10.8232 6.82322 11.2981 6.82322 11.591 6.53033L13.591 4.53033C13.8839 4.23744 13.8839 3.76256 13.591 3.46967L11.591 1.46967C11.2981 1.17678 10.8232 1.17678 10.5303 1.46967Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M17.0607 9C17.8933 9 18.7 9.27703 19.3552 9.78393L19.5301 9.92784L22.1162 12.1907C22.3061 12.3569 22.5409 12.4609 22.7891 12.4909L22.9393 12.5H40.25C42.2543 12.5 43.8913 14.0724 43.9948 16.0508L44 16.25L44.0009 24.0564C43.2472 23.3816 42.4076 22.8008 41.5007 22.3322L41.5 16.25C41.5 15.6028 41.0081 15.0705 40.3778 15.0065L40.25 15L22.8474 14.9989L20.7205 17.6147C20.0559 18.4327 19.0803 18.9305 18.035 18.9933L17.8101 19L6.5 18.999V35.25C6.5 35.8972 6.99187 36.4295 7.62219 36.4935L7.75 36.5L24.5186 36.5005C24.7868 37.3812 25.1535 38.219 25.606 39.0011L7.75 39C5.74574 39 4.10873 37.4276 4.0052 35.4492L4 35.25V12.75C4 10.7457 5.57236 9.10873 7.55084 9.0052L7.75 9H17.0607ZM17.0607 11.5H7.75C7.10279 11.5 6.57047 11.9919 6.50645 12.6222L6.5 12.75V16.499L17.8101 16.5C18.1394 16.5 18.4534 16.3701 18.6858 16.142L18.7802 16.0382L20.415 14.025L17.8838 11.8093C17.6939 11.6431 17.4591 11.5391 17.2109 11.5091L17.0607 11.5ZM36 23C41.5228 23 46 27.4772 46 33C46 38.5228 41.5228 43 36 43C30.4772 43 26 38.5228 26 33C26 27.4772 30.4772 23 36 23ZM35.9991 27.6342L35.8871 27.7097L35.7929 27.7929L35.7097 27.8871C35.4301 28.2467 35.4301 28.7533 35.7097 29.1129L35.7929 29.2071L38.585 32H31L30.8834 32.0067C30.4243 32.0601 30.06 32.4243 30.0067 32.8834L30 33L30.0067 33.1166C30.06 33.5757 30.4243 33.9399 30.8834 33.9933L31 34H38.585L35.7929 36.7929L35.7097 36.8871C35.4047 37.2794 35.4324 37.8466 35.7929 38.2071C36.1534 38.5676 36.7206 38.5953 37.1129 38.2903L37.2071 38.2071L41.7071 33.7071L41.7578 33.6525L41.8296 33.5585L41.8751 33.4843L41.9063 33.4232L41.9503 33.3121L41.9726 33.2335L41.9932 33.1175L42 33L41.997 32.924L41.9798 32.7992L41.9505 32.6883L41.9288 32.6287L41.8753 32.5159L41.8296 32.4415L41.7872 32.3833L41.7485 32.3369L41.7071 32.2929L37.2071 27.7929L37.1129 27.7097C36.7893 27.4581 36.3465 27.4329 35.9991 27.6342Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M31.8176 5.54984L42.4502 16.1824C44.7427 18.475 44.1155 22.3398 41.2157 23.7897L30.6711 29.062C30.3788 29.2082 30.1553 29.463 30.0486 29.7719L27.3645 37.5418C26.7012 39.4617 24.257 40.0247 22.8207 38.5884L17 32.7678L7.76777 42H6V40.2322L15.2323 31L9.41167 25.1794C7.97536 23.7431 8.53836 21.2988 10.4583 20.6356L18.2281 17.9515C18.537 17.8447 18.7919 17.6213 18.938 17.329L24.2103 6.78435C25.6602 3.88447 29.525 3.25729 31.8176 5.54984Z"/>
</svg>

After

Width:  |  Height:  |  Size: 567 B

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M42.4502 16.1824L31.8176 5.54984C29.525 3.25729 25.6602 3.88447 24.2103 6.78435L18.938 17.329C18.7919 17.6213 18.537 17.8447 18.2281 17.9515L10.4583 20.6356C8.53836 21.2988 7.97536 23.7431 9.41167 25.1794L15.2323 31L6 40.2322V42H7.76777L17 32.7678L22.8207 38.5884C24.257 40.0247 26.7012 39.4617 27.3645 37.5418L30.0486 29.7719C30.1553 29.463 30.3788 29.2082 30.6711 29.062L41.2157 23.7897C44.1155 22.3398 44.7427 18.475 42.4502 16.1824ZM30.0498 7.31761L40.6824 17.9502C41.7683 19.0361 41.4713 20.8668 40.0976 21.5536L29.553 26.826C28.6761 27.2644 28.0058 28.0289 27.6856 28.9556L25.0015 36.7255C24.9412 36.9 24.719 36.9512 24.5884 36.8206L11.1794 23.4116C11.0489 23.2811 11.1 23.0589 11.2746 22.9986L19.0444 20.3144C19.9711 19.9943 20.7356 19.324 21.1741 18.447L26.4464 7.90237C27.1332 6.52875 28.9639 6.23166 30.0498 7.31761Z"/>
</svg>

After

Width:  |  Height:  |  Size: 957 B

View File

@@ -0,0 +1,3 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M28 6C35.732 6 42 12.268 42 20C42 27.732 35.732 34 28 34C24.5841 34 21.4539 32.7766 19.0237 30.7441L8.1338 41.6339C7.6457 42.122 6.8542 42.122 6.3661 41.6339C5.8779 41.1457 5.8779 40.3543 6.3661 39.8661L17.2559 28.9763C15.2234 26.5461 14 23.4159 14 20C14 12.268 20.268 6 28 6ZM39.5 20C39.5 13.6487 34.3513 8.5 28 8.5C21.6487 8.5 16.5 13.6487 16.5 20C16.5 26.3513 21.6487 31.5 28 31.5C34.3513 31.5 39.5 26.3513 39.5 20Z" />
</svg>

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -0,0 +1,4 @@
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="#585858" d="M14 9.5C11.5147 9.5 9.5 11.5147 9.5 14C9.5 16.4853 11.5147 18.5 14 18.5C15.3488 18.5 16.559 17.9066 17.3838 16.9666C18.0787 16.1745 18.5 15.1365 18.5 14C18.5 13.5401 18.431 13.0962 18.3028 12.6783C17.7382 10.838 16.0253 9.5 14 9.5ZM11 14C11 12.3431 12.3431 11 14 11C15.6569 11 17 12.3431 17 14C17 15.6569 15.6569 17 14 17C12.3431 17 11 15.6569 11 14Z"/>
<path fill="#585858" d="M21.7093 22.3947L19.9818 21.6364C19.4876 21.4197 18.9071 21.4514 18.44 21.7219C17.9729 21.9923 17.675 22.4692 17.6157 23.0065L17.408 24.8855C17.3651 25.2729 17.084 25.5917 16.7055 25.6819C14.9263 26.106 13.0725 26.106 11.2933 25.6819C10.9148 25.5917 10.6336 25.2729 10.5908 24.8855L10.3834 23.0093C10.3225 22.473 10.0112 21.9976 9.54452 21.728C9.07783 21.4585 8.51117 21.4269 8.01859 21.6424L6.29071 22.4009C5.93281 22.558 5.51493 22.4718 5.24806 22.1858C4.00474 20.8536 3.07924 19.2561 2.54122 17.5136C2.42533 17.1383 2.55922 16.7307 2.8749 16.4976L4.40219 15.3703C4.83721 15.05 5.09414 14.5415 5.09414 14.0006C5.09414 13.4597 4.83721 12.9512 4.40162 12.6305L2.87529 11.5051C2.55914 11.272 2.42513 10.8638 2.54142 10.4881C3.08038 8.74728 4.00637 7.15157 5.24971 5.82108C5.51684 5.53522 5.93492 5.44935 6.29276 5.60685L8.01296 6.36398C8.50793 6.58162 9.07696 6.54875 9.54617 6.27409C10.0133 6.00258 10.3244 5.52521 10.3844 4.98787L10.5933 3.11011C10.637 2.71797 10.9245 2.39697 11.3089 2.31131C12.19 2.11498 13.0891 2.01065 14.0131 2C14.9147 2.01041 15.8128 2.11478 16.6928 2.31143C17.077 2.39728 17.3643 2.71817 17.4079 3.11011L17.617 4.98931C17.7116 5.85214 18.4387 6.50566 19.3055 6.50657C19.5385 6.50694 19.769 6.45832 19.9843 6.36288L21.7048 5.60562C22.0626 5.44812 22.4807 5.53399 22.7478 5.81984C23.9912 7.15034 24.9172 8.74605 25.4561 10.4869C25.5723 10.8623 25.4386 11.2702 25.1228 11.5034L23.5978 12.6297C23.1628 12.9499 22.9 13.4585 22.9 13.9994C22.9 14.5402 23.1628 15.0488 23.5988 15.3697L25.1251 16.4964C25.441 16.7296 25.5748 17.1376 25.4586 17.513C24.9198 19.2536 23.9944 20.8491 22.7517 22.1799C22.4849 22.4657 22.0671 22.5518 21.7093 22.3947ZM16.263 22.1965C16.4982 21.4684 16.9889 20.8288 17.6884 20.4238C18.5702 19.9132 19.6536 19.8546 20.5841 20.2626L21.9281 20.8526C22.791 19.8537 23.4593 18.7013 23.8981 17.4551L22.7095 16.5777L22.7086 16.577C21.898 15.9799 21.4 15.0276 21.4 13.9994C21.4 12.9718 21.8974 12.0195 22.7073 11.4227L22.7085 11.4217L23.8957 10.545C23.4567 9.29874 22.7881 8.1463 21.9248 7.14764L20.5922 7.73419L20.5899 7.73521C20.1844 7.91457 19.7472 8.00716 19.3039 8.00657C17.6715 8.00447 16.3046 6.77425 16.1261 5.15459L16.1259 5.15285L15.9635 3.69298C15.3202 3.57322 14.6677 3.50866 14.013 3.50011C13.3389 3.50885 12.6821 3.57361 12.0377 3.69322L11.8751 5.15446C11.7625 6.16266 11.1793 7.05902 10.3019 7.5698C9.41937 8.08554 8.34453 8.14837 7.40869 7.73688L6.07273 7.14887C5.20949 8.14745 4.54092 9.29977 4.10196 10.5459L5.29181 11.4232C6.11115 12.0268 6.59414 12.9836 6.59414 14.0006C6.59414 15.0172 6.11142 15.9742 5.29237 16.5776L4.10161 17.4565C4.54002 18.7044 5.2085 19.8584 6.07205 20.8587L7.41742 20.2681C8.34745 19.8613 9.41573 19.9214 10.2947 20.4291C11.174 20.9369 11.7593 21.8319 11.8738 22.84L11.8744 22.8445L12.0362 24.3087C13.3326 24.5638 14.6662 24.5638 15.9626 24.3087L16.1247 22.8417C16.1491 22.6217 16.1955 22.4054 16.263 22.1965Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,317 @@
using Config.Net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FSI.BT.Tools.SystemTrayMenu.Settings
{
public class Interface
{
public interface IInterface
{
string HotKey { get; set; }
[Option(DefaultValue = "false")]
bool IsUpgraded { get; set; }
[Option(DefaultValue = "")]
string PathDirectory { get; set; }
[Option(DefaultValue = "false")]
bool SetFolderByWindowsContextMenu { get; set; }
[Option(DefaultValue = "false")]
bool SaveLogFileInApplicationDirectory { get; set; }
[Option(DefaultValue = "false")]
bool IsAutostartActivated { get; set; }
[Option(DefaultValue = "false")]
bool CheckForUpdates { get; set; }
[Option(DefaultValue = "")]
string CurrentCultureInfoName { get; set; }
[Option(DefaultValue = "100")]
int SizeInPercent { get; set; }
[Option(DefaultValue = "100")]
int IconSizeInPercent { get; set; }
[Option(DefaultValue = "150")]
int RowHeighteInPercentageTouch { get; set; }
[Option(DefaultValue = "100")]
int RowHeighteInPercentage { get; set; }
[Option(DefaultValue = "100")]
int WidthMaxInPercent { get; set; }
[Option(DefaultValue = "100")]
int HeightMaxInPercent { get; set; }
[Option(DefaultValue = "true")]
bool AppearAtTheBottomLeft { get; set; }
[Option(DefaultValue = "false")]
bool UseCustomLocation { get; set; }
[Option(DefaultValue = "600")]
int CustomLocationX { get; set; }
[Option(DefaultValue = "600")]
int CustomLocationY { get; set; }
[Option(DefaultValue = "false")]
bool AppearAtMouseLocation { get; set; }
[Option(DefaultValue = "true")]
bool AppearNextToPreviousMenu { get; set; }
[Option(DefaultValue = "150")]
int OverlappingOffsetPixels { get; set; }
[Option(DefaultValue = "true")]
bool ResolveLinksToFolders { get; set; }
[Option(DefaultValue = "false")]
bool ShowInTaskbar { get; set; }
[Option(DefaultValue = "false")]
bool SendHotkeyInsteadKillOtherInstances { get; set; }
[Option(DefaultValue = "false")]
bool SupportGamepad { get; set; }
[Option(DefaultValue = "true")]
bool OpenItemWithOneClick { get; set; }
[Option(DefaultValue = "false")]
bool OpenDirectoryWithOneClick { get; set; }
[Option(DefaultValue = "false")]
bool DragDropItemsEnabledTouch { get; set; }
[Option(DefaultValue = "true")]
bool SwipeScrollingEnabledTouch { get; set; }
[Option(DefaultValue = "true")]
bool DragDropItemsEnabled { get; set; }
[Option(DefaultValue = "false")]
bool SwipeScrollingEnabled { get; set; }
[Option(DefaultValue = "")]
string PathIcoDirectory { get; set; }
[Option(DefaultValue = "true")]
bool SortByTypeAndNameWindowsExplorerSort { get; set; }
[Option(DefaultValue = "false")]
bool SortByTypeAndDate { get; set; }
[Option(DefaultValue = "false")]
bool SortByFileExtensionAndName { get; set; }
[Option(DefaultValue = "false")]
bool SortByName { get; set; }
[Option(DefaultValue = "false")]
bool SortByDate { get; set; }
[Option(DefaultValue = "true")]
bool SystemSettingsShowHiddenFiles { get; set; }
[Option(DefaultValue = "false")]
bool NeverShowHiddenFiles { get; set; }
[Option(DefaultValue = "false")]
bool AlwaysShowHiddenFiles { get; set; }
[Option(DefaultValue = "false")]
bool ShowOnlyAsSearchResult { get; set; }
[Option(DefaultValue = "")]
string PathsAddToMainMenu { get; set; }
[Option(DefaultValue = "false")]
bool GenerateShortcutsToDrives { get; set; }
[Option(DefaultValue = "100")]
int TimeUntilOpens { get; set; }
[Option(DefaultValue = "true")]
bool StaysOpenWhenItemClicked { get; set; }
[Option(DefaultValue = "true")]
bool StaysOpenWhenFocusLost { get; set; }
[Option(DefaultValue = "400")]
int TimeUntilCloses { get; set; }
[Option(DefaultValue = "true")]
bool StaysOpenWhenFocusLostAfterEnterPressed { get; set; }
[Option(DefaultValue = "200")]
int TimeUntilClosesAfterEnterPressed { get; set; }
[Option(DefaultValue = "200")]
int ClearCacheIfMoreThanThisNumberOfItems { get; set; }
[Option(DefaultValue = "")]
string SearchPattern { get; set; }
[Option(DefaultValue = "false")]
bool UseIconFromRootFolder { get; set; }
[Option(DefaultValue = "false")]
bool RoundCorners { get; set; }
[Option(DefaultValue = "true")]
bool IsDarkModeAlwaysOn { get; set; }
[Option(DefaultValue = "false")]
bool UseFading { get; set; }
[Option(DefaultValue = "false")]
bool ShowLinkOverlay { get; set; }
[Option(DefaultValue = "false")]
bool ShowDirectoryTitleAtTop { get; set; }
[Option(DefaultValue = "true")]
bool ShowSearchBar { get; set; }
[Option(DefaultValue = "false")]
bool ShowFunctionKeyOpenFolder { get; set; }
[Option(DefaultValue = "false")]
bool ShowFunctionKeyPinMenu { get; set; }
[Option(DefaultValue = "false")]
bool ShowFunctionKeySettings { get; set; }
[Option(DefaultValue = "false")]
bool ShowFunctionKeyRestart { get; set; }
[Option(DefaultValue = "false")]
bool ShowCountOfElementsBelow { get; set; }
[Option(DefaultValue = "#CCE8FF")]
string SColorSelectedItemearchPattern { get; set; }
[Option(DefaultValue = "#CCE8FF")]
string ColorSelectedItem { get; set; }
[Option(DefaultValue = "#333333")]
string ColorDarkModeSelecetedItem { get; set; }
[Option(DefaultValue = "#99D1FF")]
string ColorSelectedItemBorder { get; set; }
[Option(DefaultValue = "#141D4B")]
string ColorDarkModeSelectedItemBorder { get; set; }
[Option(DefaultValue = "#C2F5DE")]
string ColorOpenFolder { get; set; }
[Option(DefaultValue = "#14412A")]
string ColorDarkModeOpenFolder { get; set; }
[Option(DefaultValue = "#99FFA5")]
string ColorOpenFolderBorder { get; set; }
[Option(DefaultValue = "#144B55")]
string ColorDarkModeOpenFolderBorder { get; set; }
[Option(DefaultValue = "#ffffff")]
string ColorSearchField { get; set; }
[Option(DefaultValue = "#191919")]
string ColorDarkModeSearchField { get; set; }
[Option(DefaultValue = "#ffffff")]
string ColorBackground { get; set; }
[Option(DefaultValue = "#202020")]
string ColorDarkModeBackground { get; set; }
[Option(DefaultValue = "#000000")]
string ColorBackgroundBorder { get; set; }
[Option(DefaultValue = "#000000")]
string ColorDarkModeBackgroundBorder { get; set; }
[Option(DefaultValue = "#606060")]
string ColorArrow { get; set; }
[Option(DefaultValue = "#dadada")]
string ColorArrowHoverBackground { get; set; }
[Option(DefaultValue = "#000000")]
string ColorArrowHover { get; set; }
[Option(DefaultValue = "#ffffff")]
string ColorArrowClick { get; set; }
[Option(DefaultValue = "#606060")]
string ColorArrowClickBackground { get; set; }
[Option(DefaultValue = "#dadada")]
string ColorSliderArrowsAndTrackHover { get; set; }
[Option(DefaultValue = "#cdcdcd")]
string ColorSlider { get; set; }
[Option(DefaultValue = "#a6a6a6")]
string ColorSliderHover { get; set; }
[Option(DefaultValue = "#606060")]
string ColorSliderDragging { get; set; }
[Option(DefaultValue = "#f0f0f0")]
string ColorScrollbarBackground { get; set; }
[Option(DefaultValue = "#676767")]
string ColorArrowDarkMode { get; set; }
[Option(DefaultValue = "#373737")]
string ColorArrowHoverBackgroundDarkMode { get; set; }
[Option(DefaultValue = "#676767")]
string ColorArrowHoverDarkMode { get; set; }
[Option(DefaultValue = "#171717")]
string ColorArrowClickDarkMode { get; set; }
[Option(DefaultValue = "#a6a6a6")]
string ColorArrowClickBackgroundDarkMode { get; set; }
[Option(DefaultValue = "#4d4d4d")]
string ColorSliderArrowsAndTrackHoverDarkMode { get; set; }
[Option(DefaultValue = "#4d4d4d")]
string ColorSliderDarkMode { get; set; }
[Option(DefaultValue = "#7a7a7a")]
string ColorSliderHoverDarkMode { get; set; }
[Option(DefaultValue = "#a6a6a6")]
string ColorSliderDraggingDarkMode { get; set; }
[Option(DefaultValue = "#171717")]
string ColorScrollbarBackgroundDarkMode { get; set; }
[Option(DefaultValue = "#95a0a6")]
string ColorIcons { get; set; }
[Option(DefaultValue = "#95a0a6")]
string ColorDarkModeIcons { get; set; }
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
internal class AppContextMenu
{
public event Action ClickedOpenLog;
public ContextMenuStrip Create()
{
ContextMenuStrip menu = new()
{
BackColor = SystemColors.Control,
};
AddItem(menu, "Settings", () => Global.UserInterface.SettingsForm.ShowSingleInstance());
AddSeperator(menu);
AddItem(menu, "Log File", () => ClickedOpenLog?.Invoke());
AddSeperator(menu);
//AddItem(menu, "Frequently Asked Questions", Config.ShowHelpFAQ);
AddItem(menu, "Support SystemTrayMenu", Config.ShowSupportSystemTrayMenu);
AddItem(menu, "About SystemTrayMenu", About);
//AddItem(menu, "Check for updates", () => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(showWhenUpToDate: true));
AddSeperator(menu);
AddItem(menu, "Restart", AppRestart.ByAppContextMenu);
AddItem(menu, "Exit app", Application.Exit);
return menu;
}
private static void AddSeperator(ContextMenuStrip menu)
{
menu.Items.Add(new ToolStripSeparator());
}
private static void AddItem(
ContextMenuStrip menu,
string text,
Action actionClick)
{
ToolStripMenuItem toolStripMenuItem = new()
{
Text = Translator.GetText(text),
};
toolStripMenuItem.Click += (sender, e) => actionClick();
menu.Items.Add(toolStripMenuItem);
}
private static void About()
{
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(
Assembly.GetEntryAssembly().Location);
Global.UserInterface.AboutBox aboutBox = new()
{
AppTitle = versionInfo.ProductName,
AppDescription = versionInfo.FileDescription,
AppVersion = $"Version {versionInfo.FileVersion}",
AppCopyright = versionInfo.LegalCopyright,
AppMoreInfo = versionInfo.LegalCopyright,
AppImage = SystemTrayMenu.Properties.Resources.SystemTrayMenu.ToBitmap(),
};
aboutBox.AppDetailsButton = true;
aboutBox.ShowDialog();
}
}
}

View File

@@ -0,0 +1,75 @@
// <copyright file="AppNotifyIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System;
using System.Windows.Forms;
using FSI.BT.Tools.SystemTrayMenu.Helper;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
internal class AppNotifyIcon : IDisposable
{
private readonly NotifyIcon notifyIcon = new();
public AppNotifyIcon()
{
notifyIcon.Text = "FSI.BT.Tools.SystemTrayMenu";
notifyIcon.Icon = Config.GetAppIcon();
notifyIcon.Visible = true;
AppContextMenu contextMenus = new();
contextMenus.ClickedOpenLog += ClickedOpenLog;
void ClickedOpenLog()
{
OpenLog?.Invoke();
}
notifyIcon.ContextMenuStrip = contextMenus.Create();
notifyIcon.MouseClick += NotifyIcon_MouseClick;
void NotifyIcon_MouseClick(object sender, MouseEventArgs e)
{
notifyIcon.BalloonTipText = "Hallo";
notifyIcon.ShowBalloonTip(5000);
// VerifyClick(e);
}
notifyIcon.MouseDoubleClick += NotifyIcon_MouseDoubleClick;
void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
VerifyClick(e);
}
}
public event Action Click;
public event Action OpenLog;
public void Dispose()
{
notifyIcon.Icon = null;
notifyIcon.Dispose();
}
public void LoadingStart()
{
notifyIcon.Icon = Resources.StaticResources.LoadingIcon;
}
public void LoadingStop()
{
notifyIcon.Icon = Config.GetAppIcon();
}
private void VerifyClick(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Click?.Invoke();
}
}
}
}

View File

@@ -0,0 +1,745 @@
// <copyright file="CustomScrollbar.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
[Designer(typeof(ScrollbarControlDesigner))]
public class CustomScrollbar : UserControl
{
private readonly Timer timerMouseStillClicked = new();
private float largeChange = 10;
private float smallChange = 1;
private int minimum = 0;
private int maximum = 100;
private int value = 0;
private int lastValue = 0;
private int clickPoint;
private float sliderTop = 0;
private bool sliderDown = false;
private bool sliderDragging = false;
private bool arrowUpHovered = false;
private bool sliderHovered = false;
private bool arrowDownHovered = false;
private bool trackHovered = false;
private bool mouseStillClickedMoveUp = false;
private bool mouseStillClickedMoveLarge = false;
private int timerMouseStillClickedCounter = 0;
private bool paintEnabled = false;
private int width;
public CustomScrollbar()
{
InitializeComponent();
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
timerMouseStillClicked.Interval = 30;
timerMouseStillClicked.Tick += TimerMouseStillClicked_Tick;
}
public new event EventHandler Scroll = null;
public event EventHandler ValueChanged = null;
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DefaultValue(false)]
[Category("Behavior")]
[Description("LargeChange")]
public float LargeChange
{
get => largeChange;
set
{
largeChange = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DefaultValue(false)]
[Category("Behavior")]
[Description("SmallChange")]
public float SmallChange
{
get => smallChange;
set
{
smallChange = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DefaultValue(false)]
[Category("Behavior")]
[Description("Minimum")]
public int Minimum
{
get => minimum;
set
{
minimum = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DefaultValue(false)]
[Category("Behavior")]
[Description("Maximum")]
public int Maximum
{
get => maximum;
set
{
maximum = value;
Invalidate();
}
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DefaultValue(false)]
[Category("Behavior")]
[Description("Value")]
public int Value
{
get => value;
set
{
this.value = value;
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int pixelRange = trackHeight - sliderHeight;
int realRange = GetRealRange();
float percentage = 0.0f;
if (realRange != 0)
{
percentage = this.value / (float)realRange;
}
float top = percentage * pixelRange;
sliderTop = (int)top;
Invalidate();
}
}
public int Delta => Value - lastValue;
public override bool AutoSize
{
get => base.AutoSize;
set => base.AutoSize = value;
}
public void CustomScrollbar_MouseWheel(object sender, MouseEventArgs e)
{
if (e.Delta > 0)
{
MoveUp(SmallChange * MenuDefines.Scrollspeed);
}
else
{
MoveDown(SmallChange * MenuDefines.Scrollspeed);
}
}
internal void Reset()
{
sliderTop = 0;
sliderDown = false;
sliderDragging = false;
arrowUpHovered = false;
sliderHovered = false;
arrowDownHovered = false;
trackHovered = false;
mouseStillClickedMoveUp = false;
mouseStillClickedMoveLarge = false;
timerMouseStillClickedCounter = 0;
lastValue = 0;
}
/// <summary>
/// Show the control
/// (workaround, because visible = false, was causing appearing scrollbars).
/// </summary>
/// <param name="newHeight">newHeight which to paint.</param>
internal void PaintEnable(int newHeight)
{
int newWidth = Math.Max(width, Width);
Size = new Size(newWidth, newHeight);
paintEnabled = true;
}
/// <summary>
/// Hide the control
/// (workaround, because visible = false, was causing appearing scrollbars).
/// </summary>
internal void PaintDisable()
{
if (Width > 0)
{
width = Width;
}
Size = new Size(0, 0);
paintEnabled = false;
}
protected override void Dispose(bool disposing)
{
MouseDown -= CustomScrollbar_MouseDown;
MouseMove -= CustomScrollbar_MouseMove;
MouseUp -= CustomScrollbar_MouseUp;
MouseLeave -= CustomScrollbar_MouseLeave;
timerMouseStillClicked.Tick -= TimerMouseStillClicked_Tick;
timerMouseStillClicked.Dispose();
base.Dispose(disposing);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
Color colorArrow;
Color colorArrowHoverBackground;
Color colorArrowHover;
Color colorArrowClick;
Color colorArrowClickBackground;
Color colorSliderArrowsAndTrackHover;
Color colorSlider;
Color colorSliderHover;
Color colorSliderDragging;
Color colorScrollbarBackground;
if (Config.IsDarkMode())
{
colorArrow = AppColors.ArrowDarkMode;
colorArrowHoverBackground = AppColors.ArrowHoverBackgroundDarkMode;
colorArrowHover = AppColors.ArrowHoverDarkMode;
colorArrowClick = AppColors.ArrowClickDarkMode;
colorArrowClickBackground = AppColors.ArrowClickBackgroundDarkMode;
colorSliderArrowsAndTrackHover = AppColors.SliderArrowsAndTrackHoverDarkMode;
colorSlider = AppColors.SliderDarkMode;
colorSliderHover = AppColors.SliderHoverDarkMode;
colorSliderDragging = AppColors.SliderDraggingDarkMode;
colorScrollbarBackground = AppColors.ScrollbarBackgroundDarkMode;
}
else
{
colorArrow = AppColors.Arrow;
colorArrowHoverBackground = AppColors.ArrowHoverBackground;
colorArrowHover = AppColors.ArrowHover;
colorArrowClick = AppColors.ArrowClick;
colorArrowClickBackground = AppColors.ArrowClickBackground;
colorSliderArrowsAndTrackHover = AppColors.SliderArrowsAndTrackHover;
colorSlider = AppColors.Slider;
colorSliderHover = AppColors.SliderHover;
colorSliderDragging = AppColors.SliderDragging;
colorScrollbarBackground = AppColors.ScrollbarBackground;
}
if (!paintEnabled)
{
e.Graphics.FillRectangle(
new SolidBrush(colorScrollbarBackground),
new Rectangle(0, 0, Width, Height));
return;
}
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int top = (int)sliderTop + Width;
// Draw background
Brush brushScrollbarBorder = new SolidBrush(colorScrollbarBackground);
e.Graphics.FillRectangle(brushScrollbarBorder, new Rectangle(0, 0, Width, Height));
// Draw arrowUp
SolidBrush solidBrushArrowUpBackground;
SolidBrush solidBrushArrowUp;
Pen penArrowUp;
if (timerMouseStillClicked.Enabled &&
!mouseStillClickedMoveLarge && mouseStillClickedMoveUp)
{
solidBrushArrowUpBackground = new SolidBrush(colorArrowClickBackground);
solidBrushArrowUp = new SolidBrush(colorArrowClick);
penArrowUp = new Pen(colorArrowClick, 2.5F);
}
else if (arrowUpHovered)
{
solidBrushArrowUpBackground = new SolidBrush(colorArrowHoverBackground);
solidBrushArrowUp = new SolidBrush(colorArrowHover);
penArrowUp = new Pen(colorArrowHover, 2.5F);
}
else
{
solidBrushArrowUpBackground = new SolidBrush(colorScrollbarBackground);
solidBrushArrowUp = new SolidBrush(colorArrow);
penArrowUp = new Pen(colorArrow, 2.5F);
}
e.Graphics.FillRectangle(solidBrushArrowUpBackground, GetUpArrowRectangleWithoutBorder());
int widthDevidedBy2 = Width / 2;
int widthDevidedBy6 = Width / 6;
int widthDevidedBy2PluswidthDevidedBy8 = widthDevidedBy2 + (Width / 8);
PointF pointArrowUp1 = new(widthDevidedBy2 - widthDevidedBy6, widthDevidedBy2PluswidthDevidedBy8);
PointF pointArrowUp2 = new(widthDevidedBy2 + widthDevidedBy6, widthDevidedBy2PluswidthDevidedBy8);
PointF pointArrowUp3 = new(widthDevidedBy2, widthDevidedBy2PluswidthDevidedBy8 - widthDevidedBy6);
PointF pointArrowUp4 = pointArrowUp1;
PointF[] curvePoints =
{
pointArrowUp1,
pointArrowUp2,
pointArrowUp3,
pointArrowUp4,
};
e.Graphics.FillPolygon(solidBrushArrowUp, curvePoints);
e.Graphics.DrawPolygon(penArrowUp, curvePoints);
// draw slider
SolidBrush solidBrushSlider;
if (sliderDragging)
{
solidBrushSlider = new SolidBrush(colorSliderDragging);
}
else if (sliderHovered)
{
solidBrushSlider = new SolidBrush(colorSliderHover);
}
else
{
if (arrowUpHovered || arrowDownHovered || trackHovered)
{
solidBrushSlider = new SolidBrush(colorSliderArrowsAndTrackHover);
}
else
{
solidBrushSlider = new SolidBrush(colorSlider);
}
}
Rectangle rectangleSlider = new(1, top, Width - 2, sliderHeight);
e.Graphics.FillRectangle(solidBrushSlider, rectangleSlider);
// Draw arrowDown
SolidBrush solidBrushArrowDownBackground;
SolidBrush solidBrushArrowDown;
Pen penArrowDown;
if (timerMouseStillClicked.Enabled &&
!mouseStillClickedMoveLarge && !mouseStillClickedMoveUp)
{
solidBrushArrowDownBackground = new SolidBrush(colorArrowClickBackground);
solidBrushArrowDown = new SolidBrush(colorArrowClick);
penArrowDown = new Pen(colorArrowClick, 2.5F);
}
else
if (arrowDownHovered)
{
solidBrushArrowDownBackground = new SolidBrush(colorArrowHoverBackground);
solidBrushArrowDown = new SolidBrush(colorArrowHover);
penArrowDown = new Pen(colorArrowHover, 2.5F);
}
else
{
solidBrushArrowDownBackground = new SolidBrush(colorScrollbarBackground);
solidBrushArrowDown = new SolidBrush(colorArrow);
penArrowDown = new Pen(colorArrow, 2.5F);
}
e.Graphics.FillRectangle(solidBrushArrowDownBackground, GetDownArrowRectangleWithoutBorder(trackHeight));
PointF pointArrowDown1 = new(widthDevidedBy2 - widthDevidedBy6, Height - widthDevidedBy2PluswidthDevidedBy8);
PointF pointArrowDown2 = new(widthDevidedBy2 + widthDevidedBy6, Height - widthDevidedBy2PluswidthDevidedBy8);
PointF pointArrowDown3 = new(widthDevidedBy2, Height - widthDevidedBy2PluswidthDevidedBy8 + widthDevidedBy6);
PointF pointArrowDown4 = pointArrowDown1;
PointF[] curvePointsArrowDown =
{
pointArrowDown1,
pointArrowDown2,
pointArrowDown3,
pointArrowDown4,
};
e.Graphics.FillPolygon(solidBrushArrowDown, curvePointsArrowDown);
e.Graphics.DrawPolygon(penArrowDown, curvePointsArrowDown);
}
private void TimerMouseStillClicked_Tick(object sender, EventArgs e)
{
timerMouseStillClickedCounter++;
Point pointCursor = PointToClient(Cursor.Position);
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int top = (int)sliderTop + Width;
Rectangle sliderRectangle = GetSliderRectangle(sliderHeight, top);
if (sliderRectangle.Contains(pointCursor))
{
timerMouseStillClicked.Stop();
}
else if (timerMouseStillClickedCounter > 6)
{
float change;
if (mouseStillClickedMoveLarge)
{
change = SmallChange * MenuDefines.Scrollspeed;
}
else
{
change = SmallChange;
}
if (mouseStillClickedMoveUp)
{
MoveUp(change);
}
else
{
MoveDown(change);
}
}
}
private void InitializeComponent()
{
SuspendLayout();
Name = "CustomScrollbar";
MouseDown += CustomScrollbar_MouseDown;
MouseMove += CustomScrollbar_MouseMove;
MouseUp += CustomScrollbar_MouseUp;
MouseLeave += CustomScrollbar_MouseLeave;
ResumeLayout(false);
}
private void CustomScrollbar_MouseLeave(object sender, EventArgs e)
{
arrowUpHovered = false;
sliderHovered = false;
arrowDownHovered = false;
trackHovered = false;
Refresh();
}
private void CustomScrollbar_MouseDown(object sender, MouseEventArgs e)
{
Point pointCursor = PointToClient(Cursor.Position);
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int top = (int)sliderTop + Width;
Rectangle sliderRectangle = GetSliderRectangle(sliderHeight, top);
Rectangle trackRectangle = GetTrackRectangle(trackHeight);
if (sliderRectangle.Contains(pointCursor))
{
clickPoint = pointCursor.Y - top;
sliderDown = true;
}
else if (trackRectangle.Contains(pointCursor))
{
if (e.Y < sliderRectangle.Y)
{
MoveUp(Height);
mouseStillClickedMoveUp = true;
}
else
{
MoveDown(Height);
mouseStillClickedMoveUp = false;
}
mouseStillClickedMoveLarge = true;
timerMouseStillClickedCounter = 0;
timerMouseStillClicked.Start();
}
Rectangle upArrowRectangle = GetUpArrowRectangle();
if (upArrowRectangle.Contains(pointCursor))
{
MoveUp(SmallChange);
mouseStillClickedMoveUp = true;
mouseStillClickedMoveLarge = false;
timerMouseStillClickedCounter = 0;
timerMouseStillClicked.Start();
}
Rectangle downArrowRectangle = GetDownArrowRectangle(trackHeight);
if (downArrowRectangle.Contains(pointCursor))
{
MoveDown(SmallChange);
mouseStillClickedMoveUp = false;
mouseStillClickedMoveLarge = false;
timerMouseStillClickedCounter = 0;
timerMouseStillClicked.Start();
}
}
private void MoveDown(float change)
{
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int realRange = GetRealRange();
int pixelRange = trackHeight - sliderHeight;
if (realRange > 0)
{
if (pixelRange > 0)
{
float changeForOneItem = GetChangeForOneItem(change, pixelRange);
if ((sliderTop + changeForOneItem) > pixelRange)
{
sliderTop = pixelRange;
}
else
{
sliderTop += changeForOneItem;
}
CalculateValue(pixelRange);
if (Value != lastValue)
{
ValueChanged?.Invoke(this, new EventArgs());
Scroll?.Invoke(this, new EventArgs());
lastValue = Value;
}
Invalidate();
}
}
}
private void MoveUp(float change)
{
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int realRange = GetRealRange();
int pixelRange = trackHeight - sliderHeight;
if (realRange > 0)
{
if (pixelRange > 0)
{
float changeForOneItem = GetChangeForOneItem(change, pixelRange);
if ((sliderTop - changeForOneItem) < 0)
{
sliderTop = 0;
}
else
{
sliderTop -= changeForOneItem;
}
CalculateValue(pixelRange);
if (Value != lastValue)
{
ValueChanged?.Invoke(this, new EventArgs());
Scroll?.Invoke(this, new EventArgs());
lastValue = Value;
}
Invalidate();
}
}
}
private void CustomScrollbar_MouseUp(object sender, MouseEventArgs e)
{
sliderDown = false;
sliderDragging = false;
timerMouseStillClicked.Stop();
}
private void CustomScrollbar_MouseMove(object sender, MouseEventArgs e)
{
if (sliderDown == true)
{
sliderDragging = true;
}
if (sliderDragging)
{
MoveSlider(e.Y);
}
if (Value != lastValue)
{
ValueChanged?.Invoke(this, new EventArgs());
Scroll?.Invoke(this, new EventArgs());
lastValue = Value;
}
Point pointCursor = PointToClient(Cursor.Position);
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int top = (int)sliderTop + Width;
Rectangle sliderRectangle = GetSliderRectangle(sliderHeight, top);
Rectangle trackRectangle = GetTrackRectangle(trackHeight);
if (sliderRectangle.Contains(pointCursor))
{
if (e.Button != MouseButtons.Left)
{
arrowUpHovered = false;
sliderHovered = true;
arrowDownHovered = false;
trackHovered = false;
}
}
else if (trackRectangle.Contains(pointCursor))
{
arrowUpHovered = false;
sliderHovered = false;
arrowDownHovered = false;
trackHovered = true;
}
Rectangle upArrowRectangle = GetUpArrowRectangle();
if (upArrowRectangle.Contains(pointCursor))
{
if (e.Button != MouseButtons.Left)
{
arrowUpHovered = true;
sliderHovered = false;
arrowDownHovered = false;
trackHovered = false;
}
}
Rectangle downArrowRectangle = GetDownArrowRectangle(trackHeight);
if (downArrowRectangle.Contains(pointCursor))
{
if (e.Button != MouseButtons.Left)
{
arrowUpHovered = false;
sliderHovered = false;
arrowDownHovered = true;
trackHovered = false;
}
}
Invalidate();
}
private void MoveSlider(int y)
{
int nRealRange = Maximum - Minimum;
int trackHeight = GetTrackHeight();
int sliderHeight = GetSliderHeight(trackHeight);
int spot = clickPoint;
int pixelRange = trackHeight - sliderHeight;
if (sliderDown && nRealRange > 0)
{
if (pixelRange > 0)
{
int newSliderTop = y - (Width + spot);
if (newSliderTop < 0)
{
sliderTop = 0;
}
else if (newSliderTop > pixelRange)
{
sliderTop = pixelRange;
}
else
{
sliderTop = y - (Width + spot);
}
CalculateValue(pixelRange);
Invalidate();
}
}
}
private void CalculateValue(int pixelRange)
{
float percentage = sliderTop / pixelRange;
float fValue = percentage * (Maximum - LargeChange);
value = (int)fValue;
}
private Rectangle GetSliderRectangle(int sliderHeight, int top)
{
return new Rectangle(new Point(0, top), new Size(Width + 1, sliderHeight));
}
private Rectangle GetUpArrowRectangle()
{
return new Rectangle(new Point(0, 0), new Size(Width + 1, Width));
}
private Rectangle GetUpArrowRectangleWithoutBorder()
{
return new Rectangle(new Point(1, 0), new Size(Width - 2, Width));
}
private Rectangle GetDownArrowRectangle(int trackHeight)
{
return new Rectangle(new Point(0, Width + trackHeight), new Size(Width + 1, Width));
}
private Rectangle GetDownArrowRectangleWithoutBorder(int trackHeight)
{
return new Rectangle(new Point(1, Width + trackHeight), new Size(Width - 2, Width));
}
private Rectangle GetTrackRectangle(int trackHeight)
{
return new Rectangle(new Point(0, Width), new Size(Width + 1, trackHeight));
}
private int GetRealRange()
{
return Maximum - Minimum - (int)LargeChange;
}
private float GetChangeForOneItem(float change, int pixelRange)
{
return change * pixelRange / (Maximum - LargeChange);
}
private int GetTrackHeight()
{
return Height - (Width + Width);
}
private int GetSliderHeight(int trackHeight)
{
int sliderHeight = (int)((float)LargeChange / Maximum * trackHeight);
if (sliderHeight > trackHeight)
{
sliderHeight = trackHeight;
}
if (sliderHeight < 56)
{
sliderHeight = 56;
}
return sliderHeight;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,35 @@
// <copyright file="ScrollbarControlDesigner.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System.ComponentModel;
using System.Windows.Forms.Design;
internal class ScrollbarControlDesigner : ControlDesigner
{
public override SelectionRules SelectionRules
{
get
{
SelectionRules selectionRules = base.SelectionRules;
PropertyDescriptor propDescriptor = TypeDescriptor.GetProperties(Component)["AutoSize"];
if (propDescriptor != null)
{
bool autoSize = (bool)propDescriptor.GetValue(Component);
if (autoSize)
{
selectionRules = SelectionRules.Visible | SelectionRules.Moveable | SelectionRules.BottomSizeable | SelectionRules.TopSizeable;
}
else
{
selectionRules = SelectionRules.Visible | SelectionRules.AllSizeable | SelectionRules.Moveable;
}
}
return selectionRules;
}
}
}
}

View File

@@ -0,0 +1,40 @@
// <copyright file="LabelNoCopy.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System;
using System.Windows.Forms;
/// <summary>
/// Workaround class for "Clipboard" issue on .Net Windows Forms Label (https://github.com/Hofknecht/SystemTrayMenu/issues/5)
/// On Label MouseDoubleClick the framework will copy the title text into the clipboard.
/// We avoid this by overriding the Text atrribute and use own _text attribute.
/// Text will remain unset and clipboard copy will not take place but it is still possible to get/set Text attribute as usual from outside.
/// (see: https://stackoverflow.com/questions/2519587/is-there-any-way-to-disable-the-double-click-to-copy-functionality-of-a-net-l)
///
/// Note: When you have trouble with the Visual Studio Designer not showing the GUI properly, simply build once and reopen the Designer.
/// This will place the required files into the Designer's cache and becomes able to show the GUI as usual.
/// </summary>
public class LabelNoCopy : Label
{
private string text;
public override string Text
{
get => text;
set
{
value ??= string.Empty;
if (text != value)
{
text = value;
Refresh();
OnTextChanged(EventArgs.Empty);
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
// <copyright file="Language.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
public class Language
{
public string Name { get; set; }
public string Value { get; set; }
}
}

View File

@@ -0,0 +1,149 @@
// <copyright file="Menu.ControlsTheDesignerRemoves.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System.Drawing;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.Utilities;
internal partial class Menu
{
public bool IsLoadingMenu { get; internal set; }
private void InitializeComponentControlsTheDesignerRemoves()
{
DataGridViewCellStyle dataGridViewCellStyle1 = new();
DataGridViewCellStyle dataGridViewCellStyle2 = new();
DataGridViewCellStyle dataGridViewCellStyle3 = new();
labelTitle = new LabelNoCopy();
ColumnText = new DataGridViewTextBoxColumn();
ColumnIcon = new DataGridViewImageColumn();
customScrollbar = new CustomScrollbar();
tableLayoutPanelDgvAndScrollbar.Controls.Add(customScrollbar, 1, 0);
// tableLayoutPanelDgvAndScrollbar.SuspendLayout();
// ((System.ComponentModel.ISupportInitialize)dgv).BeginInit();
// tableLayoutPanelSearch.SuspendLayout();
// ((System.ComponentModel.ISupportInitialize)pictureBoxSearch).BeginInit();
// tableLayoutPanelMenu.SuspendLayout();
// SuspendLayout();
// labelTitle
labelTitle.AutoEllipsis = true;
labelTitle.AutoSize = true;
labelTitle.Dock = DockStyle.Fill;
labelTitle.Font = new Font("Segoe UI", 8.25F * Scaling.Factor, FontStyle.Bold, GraphicsUnit.Point, 0);
labelTitle.ForeColor = Color.Black;
labelTitle.Location = new Point(0, 0);
labelTitle.Margin = new Padding(0);
labelTitle.Name = "labelTitle";
labelTitle.Padding = new Padding(3, 0, 0, 1);
labelTitle.Size = new Size(70, 14);
labelTitle.Text = "FSI.BT.Tools.SystemTrayMenu";
labelTitle.TextAlign = ContentAlignment.MiddleCenter;
labelTitle.MouseWheel += new MouseEventHandler(DgvMouseWheel);
labelTitle.MouseDown += Menu_MouseDown;
labelTitle.MouseUp += Menu_MouseUp;
labelTitle.MouseMove += Menu_MouseMove;
// tableLayoutPanelMenu
tableLayoutPanelMenu.MouseDown += Menu_MouseDown;
tableLayoutPanelMenu.MouseUp += Menu_MouseUp;
tableLayoutPanelMenu.MouseMove += Menu_MouseMove;
// tableLayoutPanelBottom
tableLayoutPanelBottom.MouseDown += Menu_MouseDown;
tableLayoutPanelBottom.MouseUp += Menu_MouseUp;
tableLayoutPanelBottom.MouseMove += Menu_MouseMove;
// ColumnIcon
ColumnIcon.DataPropertyName = "ColumnIcon";
dataGridViewCellStyle1.Alignment = DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle1.NullValue = "System.Drawing.Icon";
dataGridViewCellStyle1.Padding = new Padding(3, 1, 2, 1);
ColumnIcon.DefaultCellStyle = dataGridViewCellStyle1;
ColumnIcon.Frozen = true;
ColumnIcon.HeaderText = "ColumnIcon";
ColumnIcon.ImageLayout = DataGridViewImageCellLayout.Zoom;
ColumnIcon.Name = "ColumnIcon";
ColumnIcon.ReadOnly = true;
ColumnIcon.Resizable = DataGridViewTriState.False;
ColumnIcon.Width = 25;
// ColumnText
ColumnText.DataPropertyName = "ColumnText";
dataGridViewCellStyle2.Alignment = DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle2.Padding = new Padding(0, 0, 3, 0);
ColumnText.DefaultCellStyle = dataGridViewCellStyle2;
ColumnText.Frozen = true;
ColumnText.HeaderText = "ColumnText";
ColumnText.MaxInputLength = 40;
ColumnText.Name = "ColumnText";
ColumnText.ReadOnly = true;
ColumnText.Resizable = DataGridViewTriState.False;
ColumnText.SortMode = DataGridViewColumnSortMode.Programmatic;
ColumnText.Width = 25;
dgv.Columns.AddRange(new DataGridViewColumn[]
{
ColumnIcon,
ColumnText,
});
dataGridViewCellStyle3.Font = new Font("Segoe UI", 7F * Scaling.Factor, FontStyle.Regular, GraphicsUnit.Pixel, 0);
dgv.RowsDefaultCellStyle = dataGridViewCellStyle3;
dgv.RowTemplate.DefaultCellStyle.Font = new Font("Segoe UI", 9F * Scaling.Factor, FontStyle.Regular, GraphicsUnit.Point, 0);
dgv.RowTemplate.Height = 20;
dgv.RowTemplate.ReadOnly = true;
textBoxSearch.ContextMenuStrip = new ContextMenuStrip();
tableLayoutPanelMenu.Controls.Add(labelTitle, 0, 0);
// customScrollbar
customScrollbar.Location = new Point(0, 0);
customScrollbar.Name = "customScrollbar";
customScrollbar.Size = new Size(Scaling.Scale(15), 40);
pictureBoxOpenFolder.Size = new Size(
Scaling.Scale(pictureBoxOpenFolder.Width),
Scaling.Scale(pictureBoxOpenFolder.Height));
pictureBoxMenuAlwaysOpen.Size = new Size(
Scaling.Scale(pictureBoxMenuAlwaysOpen.Width),
Scaling.Scale(pictureBoxMenuAlwaysOpen.Height));
pictureBoxSettings.Size = new Size(
Scaling.Scale(pictureBoxSettings.Width),
Scaling.Scale(pictureBoxSettings.Height));
pictureBoxRestart.Size = new Size(
Scaling.Scale(pictureBoxRestart.Width),
Scaling.Scale(pictureBoxRestart.Height));
pictureBoxSearch.Size = new Size(
Scaling.Scale(pictureBoxSearch.Width),
Scaling.Scale(pictureBoxSearch.Height));
labelItems.Font = new Font("Segoe UI", 7F * Scaling.Factor, FontStyle.Bold, GraphicsUnit.Point, 0);
// tableLayoutPanelDgvAndScrollbar.ResumeLayout(false);
// ((System.ComponentModel.ISupportInitialize)dgv).EndInit();
// tableLayoutPanelSearch.ResumeLayout(false);
// tableLayoutPanelSearch.PerformLayout();
// ((System.ComponentModel.ISupportInitialize)pictureBoxSearch).EndInit();
// tableLayoutPanelMenu.ResumeLayout(false);
// tableLayoutPanelMenu.PerformLayout();
// customScrollbar.PerformLayout();
// ResumeLayout(false);
// PerformLayout();
}
}
}

View File

@@ -0,0 +1,417 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.42000
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface {
using System;
partial class Menu
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
timerUpdateIcons.Stop();
timerUpdateIcons.Tick -= TimerUpdateIcons_Tick;
timerUpdateIcons.Tick += TimerUpdateIcons_Tick_Loading;
timerUpdateIcons.Dispose();
fading.ChangeOpacity -= Fading_ChangeOpacity;
fading.Show -= Fading_Show;
fading.Hide -= Hide;
fading.Dispose();
dgv.GotFocus -= Dgv_GotFocus;
dgv.MouseEnter -= ControlsMouseEnter;
dgv.MouseLeave -= ControlsMouseLeave;
customScrollbar.GotFocus -= CustomScrollbar_GotFocus;
customScrollbar.Scroll -= CustomScrollbar_Scroll;
customScrollbar.MouseEnter -= ControlsMouseEnter;
customScrollbar.MouseLeave -= ControlsMouseLeave;
customScrollbar.Dispose();
labelTitle.MouseEnter -= ControlsMouseEnter;
labelTitle.MouseLeave -= ControlsMouseLeave;
textBoxSearch.MouseEnter -= ControlsMouseEnter;
textBoxSearch.MouseLeave -= ControlsMouseLeave;
pictureBoxOpenFolder.MouseEnter -= ControlsMouseEnter;
pictureBoxOpenFolder.MouseLeave -= ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.MouseEnter -= ControlsMouseEnter;
pictureBoxMenuAlwaysOpen.MouseLeave -= ControlsMouseLeave;
pictureBoxMenuAlwaysOpen.Paint -= PictureBoxMenuAlwaysOpen_Paint;
pictureBoxMenuAlwaysOpen.Paint -= LoadingMenu_Paint;
pictureBoxSettings.MouseEnter -= ControlsMouseEnter;
pictureBoxSettings.MouseLeave -= ControlsMouseLeave;
pictureBoxRestart.MouseEnter -= ControlsMouseEnter;
pictureBoxRestart.MouseLeave -= ControlsMouseLeave;
pictureBoxSearch.MouseEnter -= ControlsMouseEnter;
pictureBoxSearch.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelMenu.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelMenu.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelDgvAndScrollbar.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelDgvAndScrollbar.MouseLeave -= ControlsMouseLeave;
tableLayoutPanelBottom.MouseEnter -= ControlsMouseEnter;
tableLayoutPanelBottom.MouseLeave -= ControlsMouseLeave;
labelItems.MouseEnter -= ControlsMouseEnter;
labelItems.MouseLeave -= ControlsMouseLeave;
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
this.tableLayoutPanelDgvAndScrollbar = new System.Windows.Forms.TableLayoutPanel();
this.dgv = new System.Windows.Forms.DataGridView();
this.tableLayoutPanelSearch = new System.Windows.Forms.TableLayoutPanel();
this.textBoxSearch = new System.Windows.Forms.TextBox();
this.pictureBoxSearch = new System.Windows.Forms.PictureBox();
this.labelItems = new System.Windows.Forms.Label();
this.tableLayoutPanelMenu = new System.Windows.Forms.TableLayoutPanel();
this.panelLine = new System.Windows.Forms.Panel();
this.tableLayoutPanelBottom = new System.Windows.Forms.TableLayoutPanel();
this.pictureBoxRestart = new System.Windows.Forms.PictureBox();
this.pictureBoxSettings = new System.Windows.Forms.PictureBox();
this.pictureBoxMenuAlwaysOpen = new System.Windows.Forms.PictureBox();
this.pictureBoxOpenFolder = new System.Windows.Forms.PictureBox();
this.timerUpdateIcons = new System.Windows.Forms.Timer(this.components);
this.tableLayoutPanelDgvAndScrollbar.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.dgv)).BeginInit();
this.tableLayoutPanelSearch.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxSearch)).BeginInit();
this.tableLayoutPanelMenu.SuspendLayout();
this.tableLayoutPanelBottom.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxRestart)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxSettings)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxMenuAlwaysOpen)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxOpenFolder)).BeginInit();
this.SuspendLayout();
//
// tableLayoutPanelDgvAndScrollbar
//
this.tableLayoutPanelDgvAndScrollbar.AutoSize = true;
this.tableLayoutPanelDgvAndScrollbar.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanelDgvAndScrollbar.ColumnCount = 2;
this.tableLayoutPanelDgvAndScrollbar.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelDgvAndScrollbar.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelDgvAndScrollbar.Controls.Add(this.dgv, 0, 0);
this.tableLayoutPanelDgvAndScrollbar.Location = new System.Drawing.Point(3, 25);
this.tableLayoutPanelDgvAndScrollbar.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanelDgvAndScrollbar.Name = "tableLayoutPanelDgvAndScrollbar";
this.tableLayoutPanelDgvAndScrollbar.RowCount = 1;
this.tableLayoutPanelDgvAndScrollbar.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelDgvAndScrollbar.Size = new System.Drawing.Size(55, 40);
this.tableLayoutPanelDgvAndScrollbar.TabIndex = 3;
this.tableLayoutPanelDgvAndScrollbar.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DgvMouseWheel);
//
// dgv
//
this.dgv.AllowUserToAddRows = false;
this.dgv.AllowUserToDeleteRows = false;
this.dgv.AllowUserToResizeColumns = false;
this.dgv.AllowUserToResizeRows = false;
this.dgv.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.dgv.BackgroundColor = System.Drawing.Color.White;
this.dgv.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.dgv.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
this.dgv.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.Disable;
this.dgv.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
this.dgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
this.dgv.ColumnHeadersVisible = false;
this.dgv.Location = new System.Drawing.Point(0, 0);
this.dgv.Margin = new System.Windows.Forms.Padding(0);
this.dgv.Name = "dgv";
this.dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
this.dgv.RowHeadersVisible = false;
this.dgv.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel);
this.dgv.RowsDefaultCellStyle = dataGridViewCellStyle1;
this.dgv.ScrollBars = System.Windows.Forms.ScrollBars.None;
this.dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.dgv.ShowCellErrors = false;
this.dgv.ShowCellToolTips = false;
this.dgv.ShowEditingIcon = false;
this.dgv.ShowRowErrors = false;
this.dgv.Size = new System.Drawing.Size(55, 40);
this.dgv.TabIndex = 4;
this.dgv.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DgvMouseWheel);
//
// tableLayoutPanelSearch
//
this.tableLayoutPanelSearch.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.tableLayoutPanelSearch.AutoSize = true;
this.tableLayoutPanelSearch.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanelSearch.BackColor = System.Drawing.Color.White;
this.tableLayoutPanelSearch.ColumnCount = 2;
this.tableLayoutPanelSearch.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelSearch.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelSearch.Controls.Add(this.textBoxSearch, 1, 0);
this.tableLayoutPanelSearch.Controls.Add(this.pictureBoxSearch, 0, 0);
this.tableLayoutPanelSearch.Location = new System.Drawing.Point(3, 0);
this.tableLayoutPanelSearch.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanelSearch.Name = "tableLayoutPanelSearch";
this.tableLayoutPanelSearch.RowCount = 1;
this.tableLayoutPanelSearch.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelSearch.Size = new System.Drawing.Size(128, 22);
this.tableLayoutPanelSearch.TabIndex = 5;
this.tableLayoutPanelSearch.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DgvMouseWheel);
//
// textBoxSearch
//
this.textBoxSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.textBoxSearch.BackColor = System.Drawing.Color.White;
this.textBoxSearch.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.textBoxSearch.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
this.textBoxSearch.Location = new System.Drawing.Point(25, 4);
this.textBoxSearch.Margin = new System.Windows.Forms.Padding(3, 4, 3, 2);
this.textBoxSearch.MaxLength = 37;
this.textBoxSearch.Name = "textBoxSearch";
this.textBoxSearch.Size = new System.Drawing.Size(100, 15);
this.textBoxSearch.TabIndex = 0;
this.textBoxSearch.TextChanged += new System.EventHandler(this.TextBoxSearch_TextChanged);
this.textBoxSearch.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.TextBoxSearch_KeyPress);
//
// pictureBoxSearch
//
this.pictureBoxSearch.BackColor = System.Drawing.Color.White;
this.pictureBoxSearch.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.pictureBoxSearch.Location = new System.Drawing.Point(1, 1);
this.pictureBoxSearch.Margin = new System.Windows.Forms.Padding(1);
this.pictureBoxSearch.Name = "pictureBoxSearch";
this.pictureBoxSearch.Size = new System.Drawing.Size(20, 20);
this.pictureBoxSearch.TabIndex = 1;
this.pictureBoxSearch.TabStop = false;
this.pictureBoxSearch.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxSearch_Paint);
this.pictureBoxSearch.Resize += new System.EventHandler(this.PictureBox_Resize);
//
// labelItems
//
this.labelItems.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.labelItems.AutoSize = true;
this.labelItems.ForeColor = System.Drawing.Color.White;
this.labelItems.Location = new System.Drawing.Point(10, 3);
this.labelItems.Margin = new System.Windows.Forms.Padding(0, 6, 0, 0);
this.labelItems.Name = "labelItems";
this.labelItems.Size = new System.Drawing.Size(45, 15);
this.labelItems.TabIndex = 2;
this.labelItems.Text = "0 items";
//
// tableLayoutPanelMenu
//
this.tableLayoutPanelMenu.AutoSize = true;
this.tableLayoutPanelMenu.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanelMenu.ColumnCount = 1;
this.tableLayoutPanelMenu.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelMenu.Controls.Add(this.tableLayoutPanelSearch, 0, 1);
this.tableLayoutPanelMenu.Controls.Add(this.panelLine, 0, 2);
this.tableLayoutPanelMenu.Controls.Add(this.tableLayoutPanelBottom, 0, 6);
this.tableLayoutPanelMenu.Controls.Add(this.tableLayoutPanelDgvAndScrollbar, 0, 4);
this.tableLayoutPanelMenu.Location = new System.Drawing.Point(1, 1);
this.tableLayoutPanelMenu.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanelMenu.Name = "tableLayoutPanelMenu";
this.tableLayoutPanelMenu.Padding = new System.Windows.Forms.Padding(6, 0, 6, 6);
this.tableLayoutPanelMenu.RowCount = 7;
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1F));
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 2F));
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 2F));
this.tableLayoutPanelMenu.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelMenu.Size = new System.Drawing.Size(159, 89);
this.tableLayoutPanelMenu.TabIndex = 4;
this.tableLayoutPanelMenu.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DgvMouseWheel);
//
// panelLine
//
this.panelLine.AutoSize = true;
this.panelLine.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.panelLine.BackColor = System.Drawing.Color.Silver;
this.panelLine.Dock = System.Windows.Forms.DockStyle.Fill;
this.panelLine.Location = new System.Drawing.Point(3, 22);
this.panelLine.Margin = new System.Windows.Forms.Padding(0);
this.panelLine.Name = "panelLine";
this.panelLine.Size = new System.Drawing.Size(153, 1);
this.panelLine.TabIndex = 6;
//
// tableLayoutPanelBottom
//
this.tableLayoutPanelBottom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.tableLayoutPanelBottom.AutoSize = true;
this.tableLayoutPanelBottom.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanelBottom.BackColor = System.Drawing.Color.Transparent;
this.tableLayoutPanelBottom.ColumnCount = 8;
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 10F));
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 10F));
this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanelBottom.Controls.Add(this.pictureBoxRestart, 6, 0);
this.tableLayoutPanelBottom.Controls.Add(this.pictureBoxSettings, 5, 0);
this.tableLayoutPanelBottom.Controls.Add(this.pictureBoxMenuAlwaysOpen, 4, 0);
this.tableLayoutPanelBottom.Controls.Add(this.pictureBoxOpenFolder, 3, 0);
this.tableLayoutPanelBottom.Controls.Add(this.labelItems, 1, 0);
this.tableLayoutPanelBottom.Location = new System.Drawing.Point(3, 67);
this.tableLayoutPanelBottom.Margin = new System.Windows.Forms.Padding(0);
this.tableLayoutPanelBottom.Name = "tableLayoutPanelBottom";
this.tableLayoutPanelBottom.RowCount = 1;
this.tableLayoutPanelBottom.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanelBottom.Size = new System.Drawing.Size(153, 22);
this.tableLayoutPanelBottom.TabIndex = 5;
//
// pictureBoxRestart
//
this.pictureBoxRestart.BackColor = System.Drawing.Color.Transparent;
this.pictureBoxRestart.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.pictureBoxRestart.Location = new System.Drawing.Point(122, 1);
this.pictureBoxRestart.Margin = new System.Windows.Forms.Padding(1, 5, 1, 1);
this.pictureBoxRestart.Name = "pictureBoxRestart";
this.pictureBoxRestart.Size = new System.Drawing.Size(16, 16);
this.pictureBoxRestart.TabIndex = 3;
this.pictureBoxRestart.TabStop = false;
this.pictureBoxRestart.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxRestart_Paint);
this.pictureBoxRestart.MouseClick += new System.Windows.Forms.MouseEventHandler(this.PictureBoxRestart_MouseClick);
this.pictureBoxRestart.MouseEnter += new System.EventHandler(this.PictureBox_MouseEnter);
this.pictureBoxRestart.MouseLeave += new System.EventHandler(this.PictureBox_MouseLeave);
this.pictureBoxRestart.Resize += new System.EventHandler(this.PictureBox_Resize);
//
// pictureBoxSettings
//
this.pictureBoxSettings.BackColor = System.Drawing.Color.Transparent;
this.pictureBoxSettings.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.pictureBoxSettings.Location = new System.Drawing.Point(100, 1);
this.pictureBoxSettings.Margin = new System.Windows.Forms.Padding(1, 5, 1, 1);
this.pictureBoxSettings.Name = "pictureBoxSettings";
this.pictureBoxSettings.Size = new System.Drawing.Size(16, 16);
this.pictureBoxSettings.TabIndex = 2;
this.pictureBoxSettings.TabStop = false;
this.pictureBoxSettings.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxSettings_Paint);
this.pictureBoxSettings.MouseClick += new System.Windows.Forms.MouseEventHandler(this.PictureBoxSettings_MouseClick);
this.pictureBoxSettings.MouseEnter += new System.EventHandler(this.PictureBox_MouseEnter);
this.pictureBoxSettings.MouseLeave += new System.EventHandler(this.PictureBox_MouseLeave);
this.pictureBoxSettings.Resize += new System.EventHandler(this.PictureBox_Resize);
//
// pictureBoxMenuAlwaysOpen
//
this.pictureBoxMenuAlwaysOpen.BackColor = System.Drawing.Color.Transparent;
this.pictureBoxMenuAlwaysOpen.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.pictureBoxMenuAlwaysOpen.Location = new System.Drawing.Point(78, 1);
this.pictureBoxMenuAlwaysOpen.Margin = new System.Windows.Forms.Padding(1, 5, 1, 1);
this.pictureBoxMenuAlwaysOpen.Name = "pictureBoxMenuAlwaysOpen";
this.pictureBoxMenuAlwaysOpen.Size = new System.Drawing.Size(16, 16);
this.pictureBoxMenuAlwaysOpen.TabIndex = 1;
this.pictureBoxMenuAlwaysOpen.TabStop = false;
this.pictureBoxMenuAlwaysOpen.Click += new System.EventHandler(this.PictureBoxMenuAlwaysOpen_Click);
this.pictureBoxMenuAlwaysOpen.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxMenuAlwaysOpen_Paint);
this.pictureBoxMenuAlwaysOpen.DoubleClick += new System.EventHandler(this.PictureBoxMenuAlwaysOpen_Click);
this.pictureBoxMenuAlwaysOpen.MouseEnter += new System.EventHandler(this.PictureBox_MouseEnter);
this.pictureBoxMenuAlwaysOpen.MouseLeave += new System.EventHandler(this.PictureBox_MouseLeave);
this.pictureBoxMenuAlwaysOpen.Resize += new System.EventHandler(this.PictureBox_Resize);
//
// pictureBoxOpenFolder
//
this.pictureBoxOpenFolder.BackColor = System.Drawing.Color.Transparent;
this.pictureBoxOpenFolder.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.pictureBoxOpenFolder.Location = new System.Drawing.Point(56, 1);
this.pictureBoxOpenFolder.Margin = new System.Windows.Forms.Padding(1, 5, 1, 1);
this.pictureBoxOpenFolder.Name = "pictureBoxOpenFolder";
this.pictureBoxOpenFolder.Size = new System.Drawing.Size(16, 16);
this.pictureBoxOpenFolder.TabIndex = 1;
this.pictureBoxOpenFolder.TabStop = false;
this.pictureBoxOpenFolder.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxOpenFolder_Paint);
this.pictureBoxOpenFolder.MouseClick += new System.Windows.Forms.MouseEventHandler(this.PictureBoxOpenFolder_Click);
this.pictureBoxOpenFolder.MouseEnter += new System.EventHandler(this.PictureBox_MouseEnter);
this.pictureBoxOpenFolder.MouseLeave += new System.EventHandler(this.PictureBox_MouseLeave);
this.pictureBoxOpenFolder.Resize += new System.EventHandler(this.PictureBox_Resize);
//
// Controls like the scrollbar are removed when open the designer
// When adding after InitializeComponent(), then e.g. scrollbar on high dpi not more working
//
InitializeComponentControlsTheDesignerRemoves();
//
// timerUpdateIcons
//
this.timerUpdateIcons.Tick += new System.EventHandler(this.TimerUpdateIcons_Tick);
//
// Menu
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.AutoSize = true;
this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(302, 347);
this.Controls.Add(this.tableLayoutPanelMenu);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Menu";
this.Opacity = 0.01D;
this.Padding = new System.Windows.Forms.Padding(1);
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "SystemTrayMenu";
this.TopMost = true;
this.tableLayoutPanelDgvAndScrollbar.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.dgv)).EndInit();
this.tableLayoutPanelSearch.ResumeLayout(false);
this.tableLayoutPanelSearch.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxSearch)).EndInit();
this.tableLayoutPanelMenu.ResumeLayout(false);
this.tableLayoutPanelMenu.PerformLayout();
this.tableLayoutPanelBottom.ResumeLayout(false);
this.tableLayoutPanelBottom.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxRestart)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxSettings)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxMenuAlwaysOpen)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxOpenFolder)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private SystemTrayMenu.UserInterface.LabelNoCopy labelTitle;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanelDgvAndScrollbar;
private System.Windows.Forms.DataGridView dgv;
private System.Windows.Forms.DataGridViewImageColumn ColumnIcon;
private System.Windows.Forms.DataGridViewTextBoxColumn ColumnText;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanelSearch;
private System.Windows.Forms.TextBox textBoxSearch;
private System.Windows.Forms.PictureBox pictureBoxSearch;
private UserInterface.CustomScrollbar customScrollbar;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanelMenu;
private System.Windows.Forms.PictureBox pictureBoxOpenFolder;
private System.Windows.Forms.PictureBox pictureBoxMenuAlwaysOpen;
private System.Windows.Forms.Label labelItems;
private System.Windows.Forms.Timer timerUpdateIcons;
private System.Windows.Forms.PictureBox pictureBoxSettings;
private System.Windows.Forms.PictureBox pictureBoxRestart;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanelBottom;
private System.Windows.Forms.Panel panelLine;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timerUpdateIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
// <copyright file="ShellContextMenuException.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
using System.Runtime.Serialization;
[Serializable]
public class ShellContextMenuException : Exception
{
public ShellContextMenuException()
{
// Add any type-specific logic, and supply the default message.
}
public ShellContextMenuException(string message)
: base(message)
{
// Add any type-specific logic.
}
public ShellContextMenuException(string message, Exception innerException)
: base(message, innerException)
{
// Add any type-specific logic for inner exceptions.
}
protected ShellContextMenuException(
SerializationInfo info, StreamingContext context)
: base(info, context)
{
// Implement type-specific serialization constructor logic.
}
}
}

View File

@@ -0,0 +1,40 @@
// <copyright file="ShellHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Helper
{
using System;
internal static class ShellHelper
{
/// <summary>
/// Retrieves the High Word of a WParam of a WindowMessage.
/// </summary>
/// <param name="ptr">The pointer to the WParam.</param>
/// <returns>The unsigned integer for the High Word.</returns>
public static uint HiWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL);
if ((param32 & 0x80000000) == 0x80000000)
{
return param32 >> 16;
}
else
{
return (param32 >> 16) & 0xffff;
}
}
/// <summary>
/// Retrieves the Low Word of a WParam of a WindowMessage.
/// </summary>
/// <param name="ptr">The pointer to the WParam.</param>
/// <returns>The unsigned integer for the Low Word.</returns>
public static uint LoWord(IntPtr ptr)
{
uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL);
return param32 & 0xffff;
}
}
}

View File

@@ -0,0 +1,55 @@
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
partial class TaskbarForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TaskbarForm));
this.SuspendLayout();
//
// TaskbarForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.White;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
this.ClientSize = new System.Drawing.Size(159, 136);
this.DoubleBuffered = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.Name = "TaskbarForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "SystemTrayMenu";
this.LocationChanged += new System.EventHandler(this.TaskbarForm_LocationChanged);
this.ResumeLayout(false);
}
#endregion
}
}

View File

@@ -0,0 +1,39 @@
// <copyright file="TaskbarForm.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.UserInterface
{
using System.Drawing;
using System.Windows.Forms;
public partial class TaskbarForm : Form
{
public TaskbarForm()
{
InitializeComponent();
Icon = Config.GetAppIcon();
MaximumSize = new Size(10, 1);
// Opacity = 0.01f;
// (otherwise: Task View causes Explorer restart when SystemTrayMenu is open #299)
SetLocation();
}
private void TaskbarForm_LocationChanged(object sender, System.EventArgs e)
{
SetLocation();
}
/// <summary>
/// Hide below taskbar.
/// </summary>
private void SetLocation()
{
Screen screen = Screen.PrimaryScreen;
Location = new Point(
screen.Bounds.Right - Size.Width,
screen.Bounds.Bottom + 80);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// <copyright file="DataGridViewExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
internal static class DataGridViewExtensions
{
private const float WidthMin = 100f;
/// <summary>
/// dgv.AutoResizeColumns() was too slow ~45ms.
/// </summary>
/// <param name="dgv">datagridview.</param>
internal static void FastAutoSizeColumns(this DataGridView dgv)
{
using Graphics graphics = dgv.CreateGraphics();
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
float widthMax = WidthMin;
DataTable data = (DataTable)dgv.DataSource;
foreach (DataRow row in data.Rows)
{
float checkWidth = graphics.MeasureString(
((RowData)row[2]).Text + "___",
dgv.RowTemplate.DefaultCellStyle.Font).Width;
if (checkWidth > widthMax)
{
widthMax = checkWidth;
}
}
int widthMaxInPixel = (int)(Scaling.Factor * Scaling.FactorByDpi *
400f * (Global.Vars.SystemTrayMenuSettings.WidthMaxInPercent / 100f));
widthMax = Math.Min(widthMax, widthMaxInPixel);
dgv.Columns[1].Width = (int)(widthMax + 0.5);
double factorIconSizeInPercent = Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f;
// IcoWidth 100% = 21px, 175% is 33, +3+2 is padding from ColumnIcon
float icoWidth = (16 * Scaling.FactorByDpi) + 5;
dgv.Columns[0].Width = (int)((icoWidth * factorIconSizeInPercent * Scaling.Factor) + 0.5);
}
}
}

View File

@@ -0,0 +1,24 @@
// <copyright file="DirectoryBySearchPattern.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
// see also: https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using.
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System.Collections.Generic;
public static class DirectoryBySearchPattern
{
public static List<string> GetFiles(string path, string searchPatternCombined)
{
string[] searchPatterns = searchPatternCombined.Split('|');
List<string> files = new();
foreach (string searchPattern in searchPatterns)
{
files.AddRange(System.IO.Directory.GetFiles(path, searchPattern));
}
return files;
}
}
}

View File

@@ -0,0 +1,99 @@
// <copyright file="FileLnk.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.IO;
using System.Threading;
using FSI.BT.Tools.Global.Utilities;
using Shell32;
internal class FileLnk
{
public static string GetResolvedFileName(string shortcutFilename, out bool isFolder)
{
bool isFolderByShell = false;
string resolvedFilename = string.Empty;
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
resolvedFilename = GetShortcutFileNamePath(shortcutFilename, out isFolderByShell);
}
else
{
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
void StaThreadMethod(object obj)
{
resolvedFilename = GetShortcutFileNamePath(shortcutFilename, out isFolderByShell);
}
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(shortcutFilename);
staThread.Join();
}
isFolder = isFolderByShell;
return resolvedFilename;
}
public static bool IsNetworkRoot(string path)
{
return path.StartsWith(@"\\", StringComparison.InvariantCulture) &&
!path[2..].Contains('\\', StringComparison.InvariantCulture);
}
private static string GetShortcutFileNamePath(object shortcutFilename, out bool isFolder)
{
string resolvedFilename = string.Empty;
isFolder = false;
try
{
string pathOnly = Path.GetDirectoryName((string)shortcutFilename);
string filenameOnly = Path.GetFileName((string)shortcutFilename);
Shell shell = new();
Folder folder = shell.NameSpace(pathOnly);
if (folder == null)
{
Log.Info($"{nameof(GetShortcutFileNamePath)} folder == null for path:'{shortcutFilename}'");
return resolvedFilename;
}
FolderItem folderItem = folder.ParseName(filenameOnly);
if (folderItem == null)
{
Log.Info($"{nameof(GetShortcutFileNamePath)} folderItem == null for path:'{shortcutFilename}'");
return resolvedFilename;
}
ShellLinkObject link = (ShellLinkObject)folderItem.GetLink;
isFolder = link.Target.IsFolder;
if (string.IsNullOrEmpty(link.Path))
{
// https://github.com/Hofknecht/SystemTrayMenu/issues/242
// do not set CLSID key (GUID) shortcuts as resolvedFilename
if (!link.Target.Path.Contains("::{"))
{
resolvedFilename = link.Target.Path;
}
}
else
{
resolvedFilename = link.Path;
}
}
catch (UnauthorizedAccessException)
{
// https://stackoverflow.com/questions/2934420/why-do-i-get-e-accessdenied-when-reading-public-shortcuts-through-shell32
// e.g. Administrative Tools\Component Services.lnk which can not be resolved, do not spam the logfile in this case
}
catch (Exception ex)
{
Log.Warn($"shortcutFilename:'{shortcutFilename}'", ex);
}
return resolvedFilename;
}
}
}

View File

@@ -0,0 +1,329 @@
// <copyright file="IconReader.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
// see also: https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using.
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using FSI.BT.Tools.Global.DllImports;
using FSI.BT.Tools.Global.Utilities;
/// <summary>
/// Provides static methods to read system icons for folders and files.
/// </summary>
public static class IconReader
{
private static readonly ConcurrentDictionary<string, Icon> DictIconCacheMainMenu = new();
private static readonly ConcurrentDictionary<string, Icon> DictIconCacheSubMenus = new();
public enum IconSize
{
Large = 0, // 32x32 pixels
Small = 1, // 16x16 pixels
}
public enum FolderType
{
Open = 0,
Closed = 1,
}
// see https://github.com/Hofknecht/SystemTrayMenu/issues/209.
public static bool MainPreload { get; set; }
public static void Dispose(bool includingMainMenu = true)
{
if (includingMainMenu)
{
foreach (Icon icon in DictIconCacheMainMenu.Values)
{
icon?.Dispose();
}
}
foreach (Icon icon in DictIconCacheSubMenus.Values)
{
icon?.Dispose();
}
}
public static bool ClearIfCacheTooBig()
{
bool cleared = false;
if (DictIconCacheSubMenus.Count > Global.Vars.SystemTrayMenuSettings.ClearCacheIfMoreThanThisNumberOfItems)
{
Dispose(false);
DictIconCacheSubMenus.Clear();
cleared = true;
}
return cleared;
}
public static void RemoveIconFromCache(string path)
{
if (DictIconCacheMainMenu.Remove(path, out Icon iconToRemove))
{
iconToRemove?.Dispose();
}
}
public static Icon GetFileIconWithCache(
string path,
string resolvedPath,
bool linkOverlay,
bool updateIconInBackground,
bool isMainMenu,
out bool loading,
string keyPath = "")
{
loading = false;
string extension = Path.GetExtension(path);
IconSize size = IconSize.Small;
if (Scaling.Factor >= 1.25f ||
Scaling.FactorByDpi >= 1.25f ||
Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f >= 1.25f)
{
size = IconSize.Large;
}
string key = path;
if (!string.IsNullOrEmpty(keyPath))
{
key = keyPath;
}
if (IsExtensionWithSameIcon(extension))
{
key = extension + linkOverlay;
}
if (!DictIconCache(isMainMenu).TryGetValue(key, out Icon icon) &&
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
{
icon = Resources.StaticResources.LoadingIcon;
loading = true;
if (updateIconInBackground)
{
new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground()
{
DictIconCache(isMainMenu).GetOrAdd(key, GetIconSTA(path, resolvedPath, linkOverlay, size, false));
}
}
}
return icon;
}
public static Icon GetFolderIconWithCache(
string path,
bool linkOverlay,
bool updateIconInBackground,
bool isMainMenu,
out bool loading)
{
loading = false;
IconSize size = IconSize.Small;
if (Scaling.Factor >= 1.25f ||
Scaling.FactorByDpi >= 1.25f ||
Global.Vars.SystemTrayMenuSettings.IconSizeInPercent / 100f >= 1.25f)
{
// IconSize.Large returns another folder icon than windows explorer
size = IconSize.Large;
}
string key = path;
if (!DictIconCache(isMainMenu).TryGetValue(key, out Icon icon) &&
!DictIconCache(!isMainMenu).TryGetValue(key, out icon))
{
icon = Resources.StaticResources.LoadingIcon;
loading = true;
if (updateIconInBackground)
{
if (MainPreload)
{
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
}
else
{
new Thread(UpdateIconInBackground).Start();
void UpdateIconInBackground()
{
DictIconCache(isMainMenu).GetOrAdd(key, GetFolder);
}
}
}
}
Icon GetFolder(string keyExtension)
{
return GetIconSTA(path, path, linkOverlay, size, true);
}
return icon;
}
public static Icon GetIconSTA(string path, string resolvedPath, bool linkOverlay, IconSize size, bool isFolder)
{
Icon icon = null;
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
icon = GetIcon(path, resolvedPath, linkOverlay, size, isFolder);
}
else
{
Thread staThread = new(new ParameterizedThreadStart(StaThreadMethod));
void StaThreadMethod(object obj)
{
icon = GetIcon(path, resolvedPath, linkOverlay, size, isFolder);
}
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start(icon);
staThread.Join();
}
return icon;
}
public static Icon AddIconOverlay(Icon originalIcon, Icon overlay)
{
Icon icon = null;
if (originalIcon != null)
{
using Bitmap target = new(originalIcon.Width, originalIcon.Height, PixelFormat.Format32bppArgb);
using Graphics graphics = Graphics.FromImage(target);
graphics.DrawIcon(originalIcon, 0, 0);
graphics.DrawIcon(overlay, new(0, 0, originalIcon.Width + 2, originalIcon.Height + 2));
target.MakeTransparent(target.GetPixel(1, 1));
IntPtr hIcon = target.GetHicon();
icon = (Icon)Icon.FromHandle(hIcon).Clone();
NativeMethods.User32DestroyIcon(hIcon);
}
return icon;
}
private static ConcurrentDictionary<string, Icon> DictIconCache(bool isMainMenu)
{
if (isMainMenu)
{
return DictIconCacheMainMenu;
}
else
{
return DictIconCacheSubMenus;
}
}
private static bool IsExtensionWithSameIcon(string fileExtension)
{
bool isExtensionWithSameIcon = true;
List<string> extensionsWithDiffIcons = new() { string.Empty, ".EXE", ".LNK", ".ICO", ".URL" };
if (extensionsWithDiffIcons.Contains(fileExtension.ToUpperInvariant()))
{
isExtensionWithSameIcon = false;
}
return isExtensionWithSameIcon;
}
private static Icon GetIcon(string path, string resolvedPath, bool linkOverlay, IconSize size, bool isFolder)
{
Icon icon;
if (Path.GetExtension(path).Equals(".ico", StringComparison.InvariantCultureIgnoreCase))
{
icon = Icon.ExtractAssociatedIcon(path);
}
else if (Path.GetExtension(resolvedPath).Equals(".ico", StringComparison.InvariantCultureIgnoreCase) &&
File.Exists(resolvedPath))
{
icon = Icon.ExtractAssociatedIcon(resolvedPath);
if (linkOverlay)
{
icon = AddIconOverlay(icon, Properties.Resources.LinkArrow);
}
}
else
{
NativeMethods.SHFILEINFO shFileInfo = default;
uint flags = GetFlags(linkOverlay, size);
uint attribute = isFolder ? NativeMethods.FileAttributeDirectory : NativeMethods.FileAttributeNormal;
IntPtr imageList = NativeMethods.Shell32SHGetFileInfo(
path, attribute, ref shFileInfo, (uint)Marshal.SizeOf(shFileInfo), flags);
icon = GetIcon(path, linkOverlay, shFileInfo, imageList);
}
return icon;
}
private static uint GetFlags(bool linkOverlay, IconSize size)
{
uint flags = NativeMethods.ShgfiIcon | NativeMethods.ShgfiSYSICONINDEX;
if (linkOverlay)
{
flags += NativeMethods.ShgfiLINKOVERLAY;
}
if (size == IconSize.Small)
{
flags += NativeMethods.ShgfiSMALLICON;
}
else
{
flags += NativeMethods.ShgfiLARGEICON;
}
return flags;
}
private static Icon GetIcon(
string path, bool linkOverlay, NativeMethods.SHFILEINFO shFileInfo, IntPtr imageList)
{
Icon icon = null;
if (imageList != IntPtr.Zero)
{
IntPtr hIcon;
if (linkOverlay)
{
hIcon = shFileInfo.hIcon;
}
else
{
hIcon = NativeMethods.ImageList_GetIcon(
imageList, shFileInfo.iIcon, NativeMethods.IldTransparent);
}
try
{
icon = (Icon)Icon.FromHandle(hIcon).Clone();
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
}
if (!linkOverlay)
{
NativeMethods.User32DestroyIcon(hIcon);
}
NativeMethods.User32DestroyIcon(shFileInfo.hIcon);
}
return icon;
}
}
}

View File

@@ -0,0 +1,96 @@
// <copyright file="FolderOptions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Shell32;
using FSI.BT.Tools.SystemTrayMenu.DataClasses;
using FSI.BT.Tools.Global.Utilities;
internal static class FolderOptions
{
private static bool hideHiddenEntries;
private static bool hideSystemEntries;
private static IShellDispatch4 iShellDispatch4;
internal static void Initialize()
{
try
{
iShellDispatch4 = (IShellDispatch4)Activator.CreateInstance(
Type.GetTypeFromProgID("Shell.Application"));
// Using SHGetSetSettings would be much better in performance but the results are not accurate.
// We have to go for the shell interface in order to receive the correct settings:
// https://docs.microsoft.com/en-us/windows/win32/shell/ishelldispatch4-getsetting
const int SSF_SHOWALLOBJECTS = 0x00000001;
hideHiddenEntries = !iShellDispatch4.GetSetting(
SSF_SHOWALLOBJECTS);
const int SSF_SHOWSUPERHIDDEN = 0x00040000;
hideSystemEntries = !iShellDispatch4.GetSetting(
SSF_SHOWSUPERHIDDEN);
}
catch (Exception ex)
{
if (ex is ArgumentException ||
ex is NotSupportedException ||
ex is TargetInvocationException ||
ex is MethodAccessException ||
ex is MemberAccessException ||
ex is InvalidComObjectException ||
ex is MissingMethodException ||
ex is COMException ||
ex is TypeLoadException)
{
Log.Warn("Get Shell COM instance failed", ex);
}
else
{
throw;
}
}
}
internal static bool IsHidden(RowData rowData)
{
bool isDirectoryToHide = false;
if (rowData.Path.Length >= 260)
{
Log.Info($"path too long (>=260):'{rowData.Path}'");
return isDirectoryToHide;
}
try
{
FileAttributes attributes = File.GetAttributes(rowData.Path);
rowData.HiddenEntry = attributes.HasFlag(FileAttributes.Hidden);
bool systemEntry = attributes.HasFlag(
FileAttributes.Hidden | FileAttributes.System);
if (Global.Vars.SystemTrayMenuSettings.SystemSettingsShowHiddenFiles)
{
if ((hideHiddenEntries && rowData.HiddenEntry) ||
(hideSystemEntries && systemEntry))
{
isDirectoryToHide = true;
}
}
else if (rowData.HiddenEntry && Global.Vars.SystemTrayMenuSettings.NeverShowHiddenFiles)
{
isDirectoryToHide = true;
}
}
catch (Exception ex)
{
Log.Warn($"path:'{rowData.Path}'", ex);
}
return isDirectoryToHide;
}
}
}

View File

@@ -0,0 +1,24 @@
// <copyright file="FormsExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.Windows.Forms;
internal static class FormsExtensions
{
public static void HandleInvoke(this Control instance, Action action)
{
if (instance.InvokeRequired)
{
instance.Invoke(action);
}
else
{
action();
}
}
}
}

View File

@@ -0,0 +1,68 @@
// <copyright file="GenerateDriveShortcuts.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FSI.BT.Tools.Global.Utilities;
using IWshRuntimeLibrary;
internal class GenerateDriveShortcuts
{
public static void Start()
{
List<char> driveNamesToRemove = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
DriveInfo[] driveInfos = DriveInfo.GetDrives();
foreach (DriveInfo driveInfo in driveInfos)
{
driveNamesToRemove.Remove(driveInfo.Name[0]);
string linkPath = GetLinkPathFromDriveName(driveInfo.Name[..1]);
if (!System.IO.File.Exists(linkPath))
{
CreateShortcut(linkPath, driveInfo.Name);
}
}
foreach (char driveName in driveNamesToRemove)
{
string possibleShortcut = GetLinkPathFromDriveName(driveName.ToString());
try
{
System.IO.File.Delete(possibleShortcut);
}
catch (Exception ex)
{
Log.Warn($"Could not delete shortcut at path:'{possibleShortcut}'", ex);
}
}
}
private static void CreateShortcut(string linkPath, string targetPath)
{
WshShell shell = new();
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(linkPath);
shortcut.Description = "Generated by SystemTrayMenu";
shortcut.TargetPath = targetPath;
try
{
shortcut.Save();
}
catch (Exception ex)
{
Log.Warn($"Could not create shortcut at path:'{linkPath}'", ex);
}
}
private static string GetLinkPathFromDriveName(string driveName)
{
return Path.Combine(Config.Path, $" {driveName} .lnk");
}
}
}

View File

@@ -0,0 +1,97 @@
// <copyright file="SingleAppInstance.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.SystemTrayMenu.Utilities
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using FSI.BT.Tools.Global.UserInterface.HotkeyTextboxControl;
using FSI.BT.Tools.Global.Utilities;
using WindowsInput;
internal static class SingleAppInstance
{
internal static bool Initialize()
{
bool success = true;
try
{
foreach (Process p in Process.GetProcessesByName(
Process.GetCurrentProcess().ProcessName).
Where(s => s.Id != Environment.ProcessId))
{
if (Global.Vars.SystemTrayMenuSettings.SendHotkeyInsteadKillOtherInstances)
{
Keys modifiers = HotkeyControl.HotkeyModifiersFromString(Global.Vars.SystemTrayMenuSettings.HotKey);
Keys hotkey = HotkeyControl.HotkeyFromString(Global.Vars.SystemTrayMenuSettings.HotKey);
try
{
List<VirtualKeyCode> virtualKeyCodesModifiers = new();
foreach (string key in modifiers.ToString().ToUpperInvariant().Split(", "))
{
if (key == "NONE")
{
continue;
}
VirtualKeyCode virtualKeyCode = VirtualKeyCode.LWIN;
virtualKeyCode = key switch
{
"ALT" => VirtualKeyCode.MENU,
_ => (VirtualKeyCode)Enum.Parse(
typeof(VirtualKeyCode), key.ToUpperInvariant()),
};
virtualKeyCodesModifiers.Add(virtualKeyCode);
}
VirtualKeyCode virtualKeyCodeHotkey = 0;
if (Enum.IsDefined(typeof(VirtualKeyCode), (int)hotkey))
{
virtualKeyCodeHotkey = (VirtualKeyCode)(int)hotkey;
}
new InputSimulator().Keyboard.ModifiedKeyStroke(virtualKeyCodesModifiers, virtualKeyCodeHotkey);
success = false;
}
catch (Exception ex)
{
Log.Warn($"Send hoktey {Global.Vars.SystemTrayMenuSettings.HotKey} to other instance failed", ex);
}
}
if (!Global.Vars.SystemTrayMenuSettings.SendHotkeyInsteadKillOtherInstances)
{
try
{
if (!p.CloseMainWindow())
{
p.Kill();
}
p.WaitForExit();
p.Close();
}
catch (Exception ex)
{
Log.Error("Run as single instance failed", ex);
success = false;
}
}
}
}
catch (Exception ex)
{
Log.Error("Run as single instance failed", ex);
}
return success;
}
}
}