Baseline for version 2.x

Forms replaced with WPF
Migration not complete, yet
Known open points marked with TODOs
Limited and non-optimized feature set
This commit is contained in:
Peter Kirmeier 2022-10-23 00:02:31 +02:00
parent 87dbd64c73
commit 02ba400399
64 changed files with 7434 additions and 18745 deletions

View file

@ -1,91 +0,0 @@
// <copyright file="App.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu
{
using System;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using SystemTrayMenu.Business;
using SystemTrayMenu.Helper.Updater;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.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 += (s, e) => SystemEvents_DisplaySettingsChanged();
menus.LoadStarted += menuNotifyIcon.LoadingStart;
menus.LoadStopped += menuNotifyIcon.LoadingStop;
menuNotifyIcon.Click += () => menus.SwitchOpenClose(true);
menuNotifyIcon.OpenLog += Log.OpenLogFile;
menus.MainPreload();
if (Properties.Settings.Default.ShowInTaskbar)
{
taskbarForm = new TaskbarForm();
taskbarForm.FormClosed += (s, e) => Application.Exit();
taskbarForm.Deactivate += (s, e) => SetStateNormal();
taskbarForm.Resize += (s, e) => SetStateNormal();
taskbarForm.Activated += TasbkarItemActivated;
void TasbkarItemActivated(object sender, EventArgs e)
{
SetStateNormal();
taskbarForm.Activate();
taskbarForm.Focus();
menus.SwitchOpenCloseByTaskbarItem();
}
}
DllImports.NativeMethods.User32ShowInactiveTopmost(taskbarForm);
if (Properties.Settings.Default.CheckForUpdates)
{
new Thread((obj) => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(
showWhenUpToDate: false))
.Start();
}
}
public void Dispose()
{
if (taskbarForm?.InvokeRequired == true)
{
taskbarForm.Invoke(Dispose);
}
else
{
taskbarForm?.Dispose();
SystemEvents.DisplaySettingsChanged -= (s, e) => SystemEvents_DisplaySettingsChanged();
menus.Dispose();
menuNotifyIcon.Dispose();
}
}
private void SystemEvents_DisplaySettingsChanged()
{
menus.ReAdjustSizeAndLocation();
}
/// <summary>
/// This ensures that next click on taskbaritem works as activate event/click event.
/// </summary>
private void SetStateNormal()
{
if (Form.ActiveForm == taskbarForm)
{
taskbarForm.WindowState = FormWindowState.Normal;
}
}
}
}

7
Business/App.xaml Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022-2022 Peter Kirmeier -->
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SystemTrayMenu"
x:Class="SystemTrayMenu.App" ShutdownMode="OnExplicitShutdown" />

84
Business/App.xaml.cs Normal file
View file

@ -0,0 +1,84 @@
// <copyright file="App.xaml.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
#nullable enable
namespace SystemTrayMenu
{
using System;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Win32;
using SystemTrayMenu.Business;
using SystemTrayMenu.Helper.Updater;
using SystemTrayMenu.Properties;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
/// <summary>
/// App contains the notifyicon, the taskbarform and the menus.
/// </summary>
public partial class App : Application, IDisposable
{
private readonly AppNotifyIcon menuNotifyIcon = new();
private readonly Menus menus = new();
private bool isDisposed;
public App()
{
AppRestart.BeforeRestarting += Dispose;
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
menus.LoadStarted += menuNotifyIcon.LoadingStart;
menus.LoadStopped += menuNotifyIcon.LoadingStop;
menuNotifyIcon.Click += () => menus.SwitchOpenClose(true);
menuNotifyIcon.OpenLog += Log.OpenLogFile;
menus.MainPreload();
if (Settings.Default.ShowInTaskbar)
{
TaskbarLogo = new TaskbarLogo();
TaskbarLogo.Activated += (_, _) => menus.SwitchOpenCloseByTaskbarItem();
TaskbarLogo.Show();
}
if (Settings.Default.CheckForUpdates)
{
#if TODO // GITHUBUPDATE
new Thread((obj) => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(
showWhenUpToDate: false))
.Start();
#endif
}
}
public static TaskbarLogo? TaskbarLogo { get; private set; } = null;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
TaskbarLogo?.Close();
TaskbarLogo = null;
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
menus.Dispose();
menuNotifyIcon.Dispose();
isDisposed = true;
}
}
private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e)
{
menus.ReAdjustSizeAndLocation();
}
}
}

View file

@ -8,10 +8,13 @@ namespace SystemTrayMenu.Handler
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Input;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.Helper;
using SystemTrayMenu.Utilities;
using ListView = System.Windows.Controls.ListView;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class KeyboardInput : IDisposable
@ -27,17 +30,17 @@ namespace SystemTrayMenu.Handler
this.menus = menus;
}
internal event EventHandlerEmpty HotKeyPressed;
internal event Action HotKeyPressed;
internal event EventHandlerEmpty ClosePressed;
internal event Action ClosePressed;
internal event Action<DataGridView, int> RowSelected;
internal event Action<ListView, int> RowSelected;
internal event Action<int, DataGridView> RowDeselected;
internal event Action<int, ListView> RowDeselected;
internal event Action<DataGridView, int> EnterPressed;
internal event Action<ListView, int> EnterPressed;
internal event EventHandlerEmpty Cleared;
internal event Action Cleared;
internal bool InUse { get; set; }
@ -70,34 +73,35 @@ namespace SystemTrayMenu.Handler
iMenuKey = 0;
}
internal void CmdKeyProcessed(object sender, Keys keys)
internal void CmdKeyProcessed(object sender, Key keys)
{
sender ??= menus[iMenuKey];
switch (keys)
{
case Keys.Enter:
case Key.Enter:
SelectByKey(keys);
menus[iMenuKey]?.FocusTextBox();
break;
case Keys.Left:
case Key.Left:
SelectByKey(keys);
break;
case Keys.Right:
case Key.Right:
SelectByKey(keys);
break;
case Keys.Home:
case Keys.End:
case Keys.Up:
case Keys.Down:
case Keys.Escape:
case Keys.Alt | Keys.F4:
case Key.Home:
case Key.End:
case Key.Up:
case Key.Down:
case Key.Escape:
#if TODO // WPF Key Modifier!
case Key.Alt | Key.F4:
SelectByKey(keys);
break;
case Keys.Control | Keys.F:
case Key.Control | Key.F:
menus[iMenuKey]?.FocusTextBox();
break;
case Keys.Tab:
case Key.Tab:
{
Menu currentMenu = (Menu)sender;
int indexOfTheCurrentMenu = GetMenuIndex(currentMenu);
@ -116,7 +120,7 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Tab | Keys.Shift:
case Key.Tab | Key.LeftShift:
{
Menu currentMenu = (Menu)sender;
int indexOfTheCurrentMenu = GetMenuIndex(currentMenu);
@ -135,17 +139,20 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Apps:
#endif
case Key.Apps:
{
DataGridView dgv = menus[iMenuKey]?.GetDataGridView();
ListView dgv = menus[iMenuKey]?.GetDataGridView();
if (iRowKey > -1 &&
dgv.Rows.Count > iRowKey)
dgv.Items.Count > iRowKey)
{
#if TODO
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);
#endif
}
}
@ -178,12 +185,12 @@ namespace SystemTrayMenu.Handler
internal void SearchTextChanged(Menu menu, bool isSearchStringEmpty)
{
DataGridView dgv = menu.GetDataGridView();
ListView dgv = menu.GetDataGridView();
if (isSearchStringEmpty)
{
ClearIsSelectedByKey();
}
else if (dgv.Rows.Count > 0)
else if (dgv.Items.Count > 0)
{
Select(dgv, 0, true);
}
@ -194,20 +201,21 @@ namespace SystemTrayMenu.Handler
ClearIsSelectedByKey(iMenuKey, iRowKey);
}
internal void Select(DataGridView dgv, int i, bool refreshview)
internal void Select(ListView dgv, int index, bool refreshview)
{
int newiMenuKey = ((Menu)dgv.TopLevelControl).Level;
if (i != iRowKey || newiMenuKey != iMenuKey)
int newiMenuKey = ((Menu)dgv.GetParentWindow()).Level;
if (index != iRowKey || newiMenuKey != iMenuKey)
{
ClearIsSelectedByKey();
}
iRowKey = i;
iRowKey = index;
iMenuKey = newiMenuKey;
if (dgv.Rows.Count > i)
if (dgv.Items.Count > index)
{
DataGridViewRow row = dgv.Rows[i];
#if TODO
DataGridViewRow row = dgv.Items[i];
RowData rowData = (RowData)row.Cells[2].Value;
if (rowData != null)
{
@ -219,11 +227,12 @@ namespace SystemTrayMenu.Handler
row.Selected = false;
row.Selected = true;
}
#endif
}
}
private bool IsAnyMenuSelectedByKey(
ref DataGridView dgv,
ref ListView dgv,
ref Menu menuFromSelected,
ref string textselected)
{
@ -233,10 +242,11 @@ namespace SystemTrayMenu.Handler
iRowKey > -1)
{
dgv = menu.GetDataGridView();
if (dgv.Rows.Count > iRowKey)
if (dgv.Items.Count > iRowKey)
{
#if TODO
RowData rowData = (RowData)dgv.
Rows[iRowKey].Cells[2].Value;
Items[iRowKey].Cells[2].Value;
if (rowData.IsSelected)
{
isStillSelected = true;
@ -244,20 +254,21 @@ namespace SystemTrayMenu.Handler
textselected = dgv.Rows[iRowKey].
Cells[1].Value.ToString();
}
#endif
}
}
return isStillSelected;
}
private void SelectByKey(Keys keys, string keyInput = "", bool keepSelection = false)
private void SelectByKey(Key keys, string keyInput = "", bool keepSelection = false)
{
int iRowBefore = iRowKey;
int iMenuBefore = iMenuKey;
Menu menu = menus[iMenuKey];
DataGridView dgv = null;
DataGridView dgvBefore = null;
ListView dgv = null;
ListView dgvBefore = null;
Menu menuFromSelected = null;
string textselected = string.Empty;
bool isStillSelected = IsAnyMenuSelectedByKey(ref dgv, ref menuFromSelected, ref textselected);
@ -284,26 +295,31 @@ namespace SystemTrayMenu.Handler
bool toClear = false;
switch (keys)
{
case Keys.Enter:
if (iRowKey > -1 && dgv.Rows.Count > iRowKey)
case Key.Enter:
if (iRowKey > -1 && dgv.Items.Count > iRowKey)
{
RowData trigger = (RowData)dgv.Rows[iRowKey].Cells[2].Value;
RowData trigger = ((Menu.ListViewItemData)dgv.Items[iRowKey]).data;
if (trigger.IsMenuOpen || !trigger.ContainsMenu)
{
trigger.MouseClick(null, out bool toCloseByMouseClick);
#if TODO
trigger.DoubleClick(
new MouseEventArgs(MouseButtons.Left, 0, 0, 0, 0),
new MouseButtonEventArgs(MouseButtons.Left, 0, 0, 0, 0),
out bool toCloseByDoubleClick);
#else
bool toCloseByDoubleClick = false;
#endif
if (toCloseByMouseClick || toCloseByDoubleClick)
{
ClosePressed?.Invoke();
}
#if TODO
if (iRowKey > -1 && dgv.Rows.Count > iRowKey)
{
// Raise Dgv_RowPostPaint to show ProcessStarted
dgv.InvalidateRow(iRowKey);
}
#endif
}
else
{
@ -314,9 +330,9 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Up:
case Key.Up:
if (SelectMatchedReverse(dgv, iRowKey) ||
SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
SelectMatchedReverse(dgv, dgv.Items.Count - 1))
{
RowDeselected(iRowBefore, dgvBefore);
SelectRow(dgv, iRowKey);
@ -324,7 +340,7 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Down:
case Key.Down:
if (SelectMatched(dgv, iRowKey) ||
SelectMatched(dgv, 0))
{
@ -334,7 +350,7 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Home:
case Key.Home:
if (SelectMatched(dgv, 0))
{
RowDeselected(iRowBefore, dgvBefore);
@ -343,8 +359,8 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.End:
if (SelectMatchedReverse(dgv, dgv.Rows.Count - 1))
case Key.End:
if (SelectMatchedReverse(dgv, dgv.Items.Count - 1))
{
RowDeselected(iRowBefore, dgvBefore);
SelectRow(dgv, iRowKey);
@ -352,7 +368,7 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Left:
case Key.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)
@ -365,7 +381,7 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Right:
case Key.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)
@ -378,8 +394,10 @@ namespace SystemTrayMenu.Handler
}
break;
case Keys.Escape:
case Keys.Alt | Keys.F4:
case Key.Escape:
#if TODO // WPF Key Modifier!
case Key.Alt | Key.F4:
#endif
RowDeselected(iRowBefore, dgvBefore);
iMenuKey = 0;
iRowKey = -1;
@ -421,7 +439,7 @@ namespace SystemTrayMenu.Handler
}
}
private void SelectPreviousMenu(int iRowBefore, ref Menu menu, ref DataGridView dgv, DataGridView dgvBefore, ref bool toClear)
private void SelectPreviousMenu(int iRowBefore, ref Menu menu, ref ListView dgv, ListView dgvBefore, ref bool toClear)
{
if (iMenuKey > 0)
{
@ -431,6 +449,7 @@ namespace SystemTrayMenu.Handler
iRowKey = -1;
menu = menus[iMenuKey];
dgv = menu.GetDataGridView();
#if TODO
if (SelectMatched(dgv, dgv.SelectedRows[0].Index) ||
SelectMatched(dgv, 0))
{
@ -438,6 +457,7 @@ namespace SystemTrayMenu.Handler
SelectRow(dgv, iRowKey);
toClear = true;
}
#endif
}
}
else
@ -450,7 +470,7 @@ namespace SystemTrayMenu.Handler
}
}
private void SelectNextMenu(int iRowBefore, ref DataGridView dgv, DataGridView dgvBefore, Menu menuFromSelected, bool isStillSelected, ref bool toClear)
private void SelectNextMenu(int iRowBefore, ref ListView dgv, ListView dgvBefore, Menu menuFromSelected, bool isStillSelected, ref bool toClear)
{
int iMenuKeyNext = iMenuKey + 1;
if (isStillSelected)
@ -459,7 +479,7 @@ namespace SystemTrayMenu.Handler
menuFromSelected == menus[iMenuKeyNext])
{
dgv = menuFromSelected.GetDataGridView();
if (dgv.Rows.Count > 0)
if (dgv.Items.Count > 0)
{
iMenuKey += 1;
iRowKey = -1;
@ -491,16 +511,16 @@ namespace SystemTrayMenu.Handler
}
}
private void SelectRow(DataGridView dgv, int iRowKey)
private void SelectRow(ListView dgv, int iRowKey)
{
InUse = true;
RowSelected(dgv, iRowKey);
}
private bool SelectMatched(DataGridView dgv, int indexStart, string keyInput = "")
private bool SelectMatched(ListView dgv, int indexStart, string keyInput = "")
{
bool found = false;
for (int i = indexStart; i < dgv.Rows.Count; i++)
for (int i = indexStart; i < dgv.Items.Count; i++)
{
if (Select(dgv, i, keyInput))
{
@ -512,7 +532,7 @@ namespace SystemTrayMenu.Handler
return found;
}
private bool SelectMatchedReverse(DataGridView dgv, int indexStart, string keyInput = "")
private bool SelectMatchedReverse(ListView dgv, int indexStart, string keyInput = "")
{
bool found = false;
for (int i = indexStart; i > -1; i--)
@ -527,14 +547,15 @@ namespace SystemTrayMenu.Handler
return found;
}
private bool Select(DataGridView dgv, int i, string keyInput = "")
private bool Select(ListView dgv, int i, string keyInput = "")
{
bool found = false;
if (i > -1 &&
i != iRowKey &&
dgv.Rows.Count > i)
dgv.Items.Count > i)
{
DataGridViewRow row = dgv.Rows[i];
#if TODO
DataGridViewRow row = dgv.Items[i];
RowData rowData = (RowData)row.Cells[2].Value;
string text = row.Cells[1].Value.ToString();
if (text.StartsWith(keyInput, true, CultureInfo.InvariantCulture))
@ -557,6 +578,7 @@ namespace SystemTrayMenu.Handler
found = true;
}
#endif
}
return found;
@ -567,9 +589,10 @@ namespace SystemTrayMenu.Handler
Menu menu = menus[menuIndex];
if (menu != null && rowIndex > -1)
{
DataGridView dgv = menu.GetDataGridView();
if (dgv.Rows.Count > rowIndex)
ListView dgv = menu.GetDataGridView();
if (dgv.Items.Count > rowIndex)
{
#if TODO
DataGridViewRow row = dgv.Rows[rowIndex];
row.Selected = false;
RowData rowData = (RowData)row.Cells[2].Value;
@ -578,6 +601,7 @@ namespace SystemTrayMenu.Handler
rowData.IsSelected = false;
rowData.IsClicking = false;
}
#endif
}
}
}

View file

@ -11,7 +11,11 @@ namespace SystemTrayMenu.Business
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.DllImports;
using SystemTrayMenu.Handler;
@ -19,22 +23,26 @@ namespace SystemTrayMenu.Business
using SystemTrayMenu.Helpers;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static SystemTrayMenu.Utilities.IconReader;
using ListView = System.Windows.Controls.ListView;
using Menu = SystemTrayMenu.UserInterface.Menu;
using Timer = System.Windows.Forms.Timer;
using MessageBox = System.Windows.MessageBox;
using Point = System.Drawing.Point;
internal class Menus : IDisposable
{
private readonly Menu[] menus = new Menu[MenuDefines.MenusMax];
private readonly BackgroundWorker workerMainMenu = new();
private readonly List<BackgroundWorker> workersSubMenu = new();
private readonly DgvMouseRow dgvMouseRow = new();
private readonly DgvMouseRow<ListView> dgvMouseRow = new();
private readonly WaitToLoadMenu waitToOpenMenu = new();
private readonly KeyboardInput keyboardInput;
private readonly JoystickHelper joystickHelper;
private readonly List<FileSystemWatcher> watchers = new();
private readonly List<EventArgs> watcherHistory = new();
private readonly Timer timerShowProcessStartedAsLoadingIcon = new();
private readonly Timer timerStillActiveCheck = new();
private readonly DispatcherTimer timerShowProcessStartedAsLoadingIcon = new();
private readonly DispatcherTimer timerStillActiveCheck = new();
private readonly WaitLeave waitLeave = new(Properties.Settings.Default.TimeUntilCloses);
private DateTime deactivatedTime = DateTime.MinValue;
private OpenCloseState openCloseState = OpenCloseState.Default;
@ -43,7 +51,9 @@ namespace SystemTrayMenu.Business
private bool waitingForReactivate;
private int lastMouseDownRowIndex = -1;
private bool showMenuAfterMainPreload;
#if TODO
private int dragSwipeScrollingStartRowIndex = -1;
#endif
private bool isDraggingSwipeScrolling;
private bool isDragSwipeScrolled;
private bool hideSubmenuDuringRefreshSearch;
@ -61,7 +71,8 @@ namespace SystemTrayMenu.Business
if (e.Result == null)
{
// Clean up menu status IsMenuOpen for previous one
DataGridView dgvMainMenu = menus[0].GetDataGridView();
ListView dgvMainMenu = menus[0].GetDataGridView();
#if TODO
foreach (DataRow row in ((DataTable)dgvMainMenu.DataSource).Rows)
{
RowData rowDataToClear = (RowData)row[2];
@ -70,6 +81,7 @@ namespace SystemTrayMenu.Business
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
#endif
RefreshSelection(dgvMainMenu);
@ -91,7 +103,8 @@ namespace SystemTrayMenu.Business
workerMainMenu.DoWork -= LoadMenu;
menus[0] = Create(menuData, new DirectoryInfo(Config.Path).Name);
menus[0].HandleCreated += (s, e) => ExecuteWatcherHistory();
Scaling.CalculateFactorByDpi(menus[0].GetDataGridView().CreateGraphics());
Scaling.CalculateFactorByDpi(menus[0]);
IconReader.MainPreload = false;
if (showMenuAfterMainPreload)
{
@ -251,7 +264,9 @@ namespace SystemTrayMenu.Business
waitToOpenMenu.MouseEnterOk += MouseEnterOk;
dgvMouseRow.RowMouseEnter += waitToOpenMenu.MouseEnter;
dgvMouseRow.RowMouseLeave += waitToOpenMenu.MouseLeave;
#if TODO
dgvMouseRow.RowMouseLeave += Dgv_RowMouseLeave;
#endif
keyboardInput = new(menus);
keyboardInput.RegisterHotKey();
@ -261,17 +276,17 @@ namespace SystemTrayMenu.Business
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
keyboardInput.RowSelected += AdjustScrollbarToDisplayedRow;
void AdjustScrollbarToDisplayedRow(DataGridView dgv, int index)
void AdjustScrollbarToDisplayedRow(ListView dgv, int index)
{
Menu menu = (Menu)dgv.FindForm();
Menu menu = (Menu)dgv.GetParentWindow();
menu.AdjustScrollbar();
}
joystickHelper = new();
joystickHelper.KeyPressed += (key) => menus[0].Invoke(keyboardInput.CmdKeyProcessed, null, key);
joystickHelper.KeyPressed += (key) => menus[0].Dispatcher.Invoke(keyboardInput.CmdKeyProcessed, new object[] { null, key });
timerShowProcessStartedAsLoadingIcon.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed;
timerStillActiveCheck.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed + 20;
timerShowProcessStartedAsLoadingIcon.Interval = TimeSpan.FromMilliseconds(Properties.Settings.Default.TimeUntilClosesAfterEnterPressed);
timerStillActiveCheck.Interval = TimeSpan.FromMilliseconds(Properties.Settings.Default.TimeUntilClosesAfterEnterPressed + 20);
timerStillActiveCheck.Tick += (sender, e) => StillActiveTick();
void StillActiveTick()
{
@ -319,9 +334,9 @@ namespace SystemTrayMenu.Business
}
}
internal event EventHandlerEmpty LoadStarted;
internal event Action LoadStarted;
internal event EventHandlerEmpty LoadStopped;
internal event Action LoadStopped;
private enum OpenCloseState
{
@ -345,12 +360,13 @@ namespace SystemTrayMenu.Business
waitToOpenMenu.Dispose();
keyboardInput.Dispose();
joystickHelper.Dispose();
timerShowProcessStartedAsLoadingIcon.Dispose();
timerStillActiveCheck.Dispose();
timerShowProcessStartedAsLoadingIcon.Stop();
timerStillActiveCheck.Stop();
waitLeave.Dispose();
IconReader.Dispose();
DisposeMenu(menus[0]);
dgvMouseRow.Dispose();
foreach (FileSystemWatcher watcher in watchers)
{
watcher.Created -= WatcherProcessItem;
@ -424,12 +440,12 @@ namespace SystemTrayMenu.Business
// Case when Folder Dialog open
}
else if (openCloseState == OpenCloseState.Opening ||
(menus[0] != null && menus[0].Visible && openCloseState == OpenCloseState.Default))
(menus[0] != null && menus[0].Visibility == Visibility.Visible && openCloseState == OpenCloseState.Default))
{
openCloseState = OpenCloseState.Closing;
MenusFadeOut();
StopWorker();
if (!AsEnumerable.Any(m => m.Visible))
if (!AsEnumerable.Any(m => m.Visibility == Visibility.Visible))
{
openCloseState = OpenCloseState.Default;
}
@ -448,6 +464,13 @@ namespace SystemTrayMenu.Business
{
if (menuToDispose != null)
{
menuToDispose.CellMouseEnter -= dgvMouseRow.CellMouseEnter;
menuToDispose.CellMouseLeave -= dgvMouseRow.CellMouseLeave;
menuToDispose.CellMouseDown -= Dgv_MouseDown;
menuToDispose.CellMouseUp -= Dgv_MouseUp;
menuToDispose.CellMouseClick -= Dgv_MouseClick;
menuToDispose.CellMouseDoubleClick -= Dgv_MouseDoubleClick;
#if TODO
menuToDispose.MouseWheel -= AdjustMenusSizeAndLocation;
menuToDispose.MouseLeave -= waitLeave.Start;
menuToDispose.MouseEnter -= waitLeave.Stop;
@ -455,19 +478,13 @@ namespace SystemTrayMenu.Business
menuToDispose.SearchTextChanging -= keyboardInput.SearchTextChanging;
menuToDispose.KeyPressCheck -= Menu_KeyPressCheck;
menuToDispose.SearchTextChanged -= Menu_SearchTextChanged;
DataGridView dgv = menuToDispose.GetDataGridView();
ListView dgv = menuToDispose.GetDataGridView();
if (dgv != null)
{
dgv.CellMouseEnter -= dgvMouseRow.CellMouseEnter;
dgv.CellMouseLeave -= dgvMouseRow.CellMouseLeave;
dgv.MouseLeave -= dgvMouseRow.MouseLeave;
dgv.MouseLeave -= Dgv_MouseLeave;
dgv.MouseMove -= waitToOpenMenu.MouseMove;
dgv.MouseMove -= Dgv_MouseMove;
dgv.MouseDown -= Dgv_MouseDown;
dgv.MouseUp -= Dgv_MouseUp;
dgv.MouseClick -= Dgv_MouseClick;
dgv.MouseDoubleClick -= Dgv_MouseDoubleClick;
dgv.SelectionChanged -= Dgv_SelectionChanged;
dgv.RowPostPaint -= Dgv_RowPostPaint;
dgv.ClearSelection();
@ -478,8 +495,8 @@ namespace SystemTrayMenu.Business
DisposeMenu(rowData.SubMenu);
}
}
menuToDispose.Dispose();
#endif
}
}
@ -496,12 +513,12 @@ namespace SystemTrayMenu.Business
IconReader.MainPreload = true;
timerShowProcessStartedAsLoadingIcon.Tick += Tick;
timerShowProcessStartedAsLoadingIcon.Interval = 5;
timerShowProcessStartedAsLoadingIcon.Interval = TimeSpan.FromMilliseconds(5);
timerShowProcessStartedAsLoadingIcon.Start();
void Tick(object sender, EventArgs e)
{
timerShowProcessStartedAsLoadingIcon.Tick -= Tick;
timerShowProcessStartedAsLoadingIcon.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed;
timerShowProcessStartedAsLoadingIcon.Interval = TimeSpan.FromMilliseconds(Properties.Settings.Default.TimeUntilClosesAfterEnterPressed);
SwitchOpenClose(false, true);
}
}
@ -560,30 +577,31 @@ namespace SystemTrayMenu.Business
Log.ProcessStart(path);
}
private static int GetRowUnderCursor(DataGridView dgv, Point location)
private static int GetRowUnderCursor(ListView dgv, Point location)
{
DataGridView.HitTestInfo myHitTest = dgv.HitTest(location.X, location.Y);
#if TODO
ListView.HitTestInfo myHitTest = dgv.HitTest(location.X, location.Y);
return myHitTest.RowIndex;
}
private static void InvalidateRowIfIndexInRange(DataGridView dgv, int rowIndex)
{
if (rowIndex > -1 && rowIndex < dgv.Rows.Count)
{
dgv.InvalidateRow(rowIndex);
}
#else
return 0;
#endif
}
private static void AddItemsToMenu(List<RowData> data, Menu menu, out int foldersCount, out int filesCount)
{
foldersCount = 0;
filesCount = 0;
DataGridView dgv = menu.GetDataGridView();
List<Menu.ListViewItemData> items = new();
ListView lv = menu.GetDataGridView();
#if TODO // REMOVE?
DataTable dataTable = new();
dataTable.Columns.Add(dgv.Columns[0].Name, typeof(Icon));
dataTable.Columns.Add(dgv.Columns[1].Name, typeof(string));
dataTable.Columns.Add("data", typeof(RowData));
dataTable.Columns.Add("SortIndex");
foreach (var prop in typeof(Menu.ListViewItemData).GetProperties())
{
dataTable.Columns.Add(prop.Name, prop.PropertyType);
}
foreach (RowData rowData in data)
{
if (!(rowData.IsAddionalItem && Properties.Settings.Default.ShowOnlyAsSearchResult))
@ -601,23 +619,45 @@ namespace SystemTrayMenu.Business
rowData.SetData(rowData, dataTable);
}
dgv.DataSource = dataTable;
dgv.Columns["data"].Visible = false;
dgv.Columns["SortIndex"].Visible = false;
lv.ItemsSource = dataTable.DefaultView;
string columnSortIndex = "SortIndex";
foreach (DataRow row in dataTable.Rows)
{
RowData rowData = (RowData)row[2];
RowData rowData = (RowData)row[nameof(Menu.ListViewItemData.data)];
if (rowData.IsAddionalItem && Properties.Settings.Default.ShowOnlyAsSearchResult)
{
row[columnSortIndex] = 99;
row[nameof(Menu.ListViewItemData.SortIndex)] = 99;
}
else
{
row[columnSortIndex] = 0;
row[nameof(Menu.ListViewItemData.SortIndex)] = 0;
}
}
#else
foreach (RowData rowData in data)
{
if (!(rowData.IsAddionalItem && Properties.Settings.Default.ShowOnlyAsSearchResult))
{
if (rowData.ContainsMenu)
{
foldersCount++;
}
else
{
filesCount++;
}
}
rowData.RowIndex = items.Count; // Index
items.Add(new(
rowData.HiddenEntry ? AddIconOverlay(rowData.Icon, Properties.Resources.White50Percentage) : rowData.Icon,
rowData.Text,
rowData,
rowData.IsAddionalItem && Properties.Settings.Default.ShowOnlyAsSearchResult ? 99 : 0));
}
lv.ItemsSource = items;
#endif
}
private bool IsActive()
@ -627,8 +667,9 @@ namespace SystemTrayMenu.Business
bool isShellContextMenuOpen = false;
foreach (Menu menu in menus.Where(m => m != null))
{
DataGridView dgv = menu.GetDataGridView();
foreach (DataGridViewRow row in dgv.Rows)
ListView dgv = menu.GetDataGridView();
#if TODO
foreach (DataGridViewRow row in dgv.Items)
{
RowData rowData = (RowData)row.Cells[2].Value;
if (rowData != null && rowData.IsContextMenuOpen)
@ -637,6 +678,7 @@ namespace SystemTrayMenu.Business
break;
}
}
#endif
if (isShellContextMenuOpen)
{
@ -647,7 +689,12 @@ namespace SystemTrayMenu.Business
return isShellContextMenuOpen;
}
return Form.ActiveForm is Menu or TaskbarForm || IsShellContextMenuOpen();
foreach (Menu menu in menus.Where(m => m != null && m.IsActive))
{
return true;
}
return (App.TaskbarLogo != null && App.TaskbarLogo.IsActive) || IsShellContextMenuOpen();
}
private Menu Create(MenuData menuData, string title = null)
@ -661,14 +708,12 @@ namespace SystemTrayMenu.Business
path = menuData.RowDataParent.ResolvedPath;
}
if (string.IsNullOrEmpty(title))
{
title = Path.GetPathRoot(path);
}
title ??= Path.GetPathRoot(path);
menu.AdjustControls(title, menuData.Validity);
menu.UserClickedOpenFolder += () => OpenFolder(path);
menu.Level = menuData.Level;
#if TODO
menu.MouseWheel += AdjustMenusSizeAndLocation;
menu.MouseLeave += waitLeave.Start;
menu.MouseEnter += waitLeave.Stop;
@ -676,6 +721,7 @@ namespace SystemTrayMenu.Business
menu.KeyPressCheck += Menu_KeyPressCheck;
menu.SearchTextChanging += Menu_SearchTextChanging;
menu.SearchTextChanged += Menu_SearchTextChanged;
#endif
menu.UserDragsMenu += Menu_UserDragsMenu;
void Menu_UserDragsMenu()
{
@ -685,7 +731,7 @@ namespace SystemTrayMenu.Business
}
}
menu.Deactivate += Deactivate;
menu.Deactivated += Deactivate;
void Deactivate(object sender, EventArgs e)
{
if (IsOpenCloseStateOpening())
@ -714,19 +760,22 @@ namespace SystemTrayMenu.Business
}
}
menu.VisibleChanged += MenuVisibleChanged;
menu.IsVisibleChanged += (sender, _) => MenuVisibleChanged(sender, new EventArgs());
AddItemsToMenu(menuData.RowDatas, menu, out int foldersCount, out int filesCount);
DataGridView dgv = menu.GetDataGridView();
dgv.CellMouseEnter += dgvMouseRow.CellMouseEnter;
dgv.CellMouseLeave += dgvMouseRow.CellMouseLeave;
menu.CellMouseEnter += dgvMouseRow.CellMouseEnter;
menu.CellMouseLeave += dgvMouseRow.CellMouseLeave;
menu.CellMouseDown += Dgv_MouseDown;
menu.CellMouseUp += Dgv_MouseUp;
menu.CellMouseClick += Dgv_MouseClick;
menu.CellMouseDoubleClick += Dgv_MouseDoubleClick;
#if TODO
ListView dgv = menu.GetDataGridView();
dgv.MouseLeave += dgvMouseRow.MouseLeave;
dgv.MouseLeave += Dgv_MouseLeave;
dgv.MouseMove += waitToOpenMenu.MouseMove;
dgv.MouseMove += Dgv_MouseMove;
dgv.MouseDown += Dgv_MouseDown;
dgv.MouseUp += Dgv_MouseUp;
dgv.MouseClick += Dgv_MouseClick;
dgv.MouseDoubleClick += Dgv_MouseDoubleClick;
dgv.SelectionChanged += Dgv_SelectionChanged;
dgv.RowPostPaint += Dgv_RowPostPaint;
@ -737,7 +786,7 @@ namespace SystemTrayMenu.Business
// => Rare times occured (e.g. when focused an close other application => closed and activated at same time)
Log.Warn("Dgv_DataError occured", e.Exception);
}
#endif
menu.SetCounts(foldersCount, filesCount);
return menu;
@ -758,12 +807,12 @@ namespace SystemTrayMenu.Business
}
}
if (!menu.Visible && menu.Level != 0)
if (menu.Visibility != Visibility.Visible && menu.Level != 0)
{
DisposeMenu(menu);
}
if (!AsEnumerable.Any(m => m.Visible))
if (!AsEnumerable.Any(m => m.Visibility == Visibility.Visible))
{
if (IconReader.ClearIfCacheTooBig())
{
@ -778,7 +827,8 @@ namespace SystemTrayMenu.Business
{
if (isDraggingSwipeScrolling)
{
DataGridView dgv = (DataGridView)sender;
#if TODO
ListView dgv = (ListView)sender;
int newRow = GetRowUnderCursor(dgv, e.Location);
if (newRow > -1)
{
@ -788,14 +838,16 @@ namespace SystemTrayMenu.Business
dragSwipeScrollingStartRowIndex += delta;
}
}
#endif
}
}
private bool DoScroll(DataGridView dgv, ref int delta)
private bool DoScroll(ListView dgv, ref int delta)
{
bool scrolled = false;
if (delta != 0)
{
#if TODO
if (delta < 0 && dgv.FirstDisplayedScrollingRowIndex == 0)
{
delta = 0;
@ -812,35 +864,31 @@ namespace SystemTrayMenu.Business
{
isDragSwipeScrolled = true;
dgv.FirstDisplayedScrollingRowIndex = newFirstDisplayedScrollingRowIndex;
Menu menu = (Menu)dgv.FindForm();
Menu menu = (Menu)dgv.GetParentWindow();
menu.AdjustScrollbar();
scrolled = dgv.FirstDisplayedScrollingRowIndex == newFirstDisplayedScrollingRowIndex;
}
#endif
}
return scrolled;
}
private void Dgv_MouseDown(object sender, MouseEventArgs e)
private void Dgv_MouseDown(object sender, int index, MouseButtonEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridView.HitTestInfo hitTestInfo;
hitTestInfo = dgv.HitTest(e.X, e.Y);
if (hitTestInfo.RowIndex > -1 &&
hitTestInfo.RowIndex < dgv.Rows.Count)
{
MouseEnterOk(dgv, hitTestInfo.RowIndex, true);
RowData rowData = (RowData)dgv.Rows[hitTestInfo.RowIndex].Cells[2].Value;
rowData.MouseDown(dgv, e);
InvalidateRowIfIndexInRange(dgv, hitTestInfo.RowIndex);
}
ListView dgv = (ListView)sender;
if (e.Button == MouseButtons.Left)
{
lastMouseDownRowIndex = hitTestInfo.RowIndex;
}
MouseEnterOk(dgv, index, true);
Menu menu = (Menu)((DataGridView)sender).FindForm();
// TODO WPF: Move directly into ListViewItem_MouseDown ?
((Menu.ListViewItemData)dgv.Items[index]).data.MouseDown(dgv, e);
if (e.LeftButton == MouseButtonState.Pressed)
{
lastMouseDownRowIndex = index;
}
#if TODO
Menu menu = (Menu)((ListView)sender).GetParentWindow();
if (menu != null && menu.ScrollbarVisible)
{
bool isTouchEnabled = DllImports.NativeMethods.IsTouchEnabled();
@ -852,17 +900,14 @@ namespace SystemTrayMenu.Business
dragSwipeScrollingStartRowIndex = GetRowUnderCursor(dgv, e.Location);
}
#endif
}
private void Dgv_MouseUp(object sender, MouseEventArgs e)
private void Dgv_MouseUp(object sender, int index, MouseButtonEventArgs e)
{
lastMouseDownRowIndex = -1;
isDraggingSwipeScrolling = false;
isDragSwipeScrolled = false;
// In case during mouse down move mouse out of dgv (it has own scrollbehavior) which we need to refresh
Menu menu = (Menu)((DataGridView)sender).FindForm();
menu.AdjustScrollbar();
}
private void Dgv_MouseLeave(object sender, EventArgs e)
@ -871,12 +916,12 @@ namespace SystemTrayMenu.Business
isDragSwipeScrolled = false;
}
private void MouseEnterOk(DataGridView dgv, int rowIndex)
private void MouseEnterOk(ListView dgv, int rowIndex)
{
MouseEnterOk(dgv, rowIndex, false);
}
private void MouseEnterOk(DataGridView dgv, int rowIndex, bool refreshView)
private void MouseEnterOk(ListView dgv, int rowIndex, bool refreshView)
{
if (menus[0].IsUsable)
{
@ -889,41 +934,42 @@ namespace SystemTrayMenu.Business
keyboardInput.Select(dgv, rowIndex, refreshView);
}
}
#if TODO
private void Dgv_RowMouseLeave(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
ListView dgv = (ListView)sender;
if (!isDragSwipeScrolled &&
e.RowIndex == lastMouseDownRowIndex &&
e.RowIndex > -1 &&
e.RowIndex < dgv.Rows.Count)
e.RowIndex < dgv.Items.Count)
{
lastMouseDownRowIndex = -1;
RowData rowData = (RowData)dgv.Rows[e.RowIndex].Cells[2].Value;
#if TODO
RowData rowData = (RowData)dgv.Items[e.RowIndex].Cells[2].Value;
string[] files = new string[] { rowData.Path };
// Update position raises move event which prevent DoDragDrop blocking UI when mouse not moved
Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y);
dgv.DoDragDrop(new DataObject(DataFormats.FileDrop, files), DragDropEffects.Copy);
#endif
}
}
#endif
private void Dgv_MouseClick(object sender, MouseEventArgs e)
private void Dgv_MouseClick(object sender, int index, MouseButtonEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridView.HitTestInfo hitTestInfo;
hitTestInfo = dgv.HitTest(e.X, e.Y);
if (!isDragSwipeScrolled &&
hitTestInfo.RowIndex == lastMouseDownRowIndex &&
hitTestInfo.RowIndex > -1 &&
hitTestInfo.RowIndex < dgv.Rows.Count)
if (!isDragSwipeScrolled)
{
ListView dgv = (ListView)sender;
lastMouseDownRowIndex = -1;
RowData rowData = (RowData)dgv.Rows[hitTestInfo.RowIndex].Cells[2].Value;
rowData.MouseClick(e, out bool toCloseByClick);
waitToOpenMenu.ClickOpensInstantly(dgv, hitTestInfo.RowIndex);
// TODO WPF: Move directly into ListViewxItem_PreviewMouseLeftButtonDown ?
((Menu.ListViewItemData)dgv.Items[index]).data.MouseClick(e, out bool toCloseByClick);
waitToOpenMenu.ClickOpensInstantly(dgv, index);
if (toCloseByClick)
{
MenusFadeOut();
@ -933,22 +979,17 @@ namespace SystemTrayMenu.Business
lastMouseDownRowIndex = -1;
}
private void Dgv_MouseDoubleClick(object sender, MouseEventArgs e)
private void Dgv_MouseDoubleClick(object sender, int index, MouseButtonEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridView.HitTestInfo hitTestInfo;
hitTestInfo = dgv.HitTest(e.X, e.Y);
if (hitTestInfo.RowIndex > -1 &&
dgv.Rows.Count > hitTestInfo.RowIndex)
ListView dgv = (ListView)sender;
lastMouseDownRowIndex = -1;
// TODO WPF: Move directly into ListViewItem_MouseDoubleClick ?
((Menu.ListViewItemData)dgv.Items[index]).data.DoubleClick(e, out bool toCloseByDoubleClick);
if (toCloseByDoubleClick)
{
lastMouseDownRowIndex = -1;
RowData rowData = (RowData)dgv.Rows[hitTestInfo.RowIndex].Cells[2].Value;
rowData.DoubleClick(e, out bool toCloseByDoubleClick);
InvalidateRowIfIndexInRange(dgv, hitTestInfo.RowIndex);
if (toCloseByDoubleClick)
{
MenusFadeOut();
}
MenusFadeOut();
}
lastMouseDownRowIndex = -1;
@ -956,15 +997,16 @@ namespace SystemTrayMenu.Business
private void Dgv_SelectionChanged(object sender, EventArgs e)
{
RefreshSelection((DataGridView)sender);
RefreshSelection((ListView)sender);
}
private void RefreshSelection(DataGridView dgv)
private void RefreshSelection(ListView dgv)
{
dgv.SelectionChanged -= Dgv_SelectionChanged;
foreach (DataGridViewRow row in dgv.Rows)
foreach (Menu.ListViewItemData row in dgv.Items)
{
RowData rowData = (RowData)row.Cells[2].Value;
RowData rowData = row.data;
if (rowData == null)
{
@ -972,31 +1014,39 @@ namespace SystemTrayMenu.Business
}
else if (!menus[0].IsUsable)
{
#if TODO
row.DefaultCellStyle.SelectionBackColor = Color.White;
row.Selected = false;
#endif
dgv.SelectedItems.Remove(row);
}
else if (rowData.IsClicking)
{
#if TODO
row.DefaultCellStyle.SelectionBackColor = MenuDefines.ColorIcons;
row.Selected = true;
#endif
dgv.SelectedItems.Add(row);
}
else if (rowData.IsContextMenuOpen || (rowData.IsMenuOpen && rowData.IsSelected))
{
row.Selected = true;
dgv.SelectedItems.Add(row);
}
else if (rowData.IsMenuOpen)
{
row.Selected = true;
dgv.SelectedItems.Add(row);
}
else if (rowData.IsSelected)
{
#if TODO
row.DefaultCellStyle.SelectionBackColor = MenuDefines.ColorSelectedItem;
row.Selected = true;
#endif
dgv.SelectedItems.Add(row);
}
else
{
#if TODO
row.DefaultCellStyle.SelectionBackColor = Color.White;
row.Selected = false;
#endif
dgv.SelectedItems.Remove(row);
}
}
@ -1004,14 +1054,17 @@ namespace SystemTrayMenu.Business
if (!searchTextChanging)
{
#if TODO
dgv.Invalidate();
#endif
}
}
#if TODO
private void Dgv_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridViewRow row = dgv.Rows[e.RowIndex];
ListView dgv = (ListView)sender;
DataGridViewRow row = dgv.Items[e.RowIndex];
if (row.Selected)
{
@ -1056,7 +1109,8 @@ namespace SystemTrayMenu.Business
timerStillActiveCheck.Start();
}
}
}
}
#endif
private void ShowSubMenu(Menu menuToShow)
{
@ -1072,7 +1126,8 @@ namespace SystemTrayMenu.Business
if (menuPrevious != null)
{
// Clean up menu status IsMenuOpen for previous one
DataGridView dgvPrevious = menuPrevious.GetDataGridView();
ListView dgvPrevious = menuPrevious.GetDataGridView();
#if TODO
foreach (DataRow row in ((DataTable)dgvPrevious.DataSource).Rows)
{
RowData rowDataToClear = (RowData)row[2];
@ -1085,6 +1140,7 @@ namespace SystemTrayMenu.Business
rowDataToClear.IsMenuOpen = false;
}
}
#endif
RefreshSelection(dgvPrevious);
@ -1104,9 +1160,8 @@ namespace SystemTrayMenu.Business
{
if (!IsActive())
{
Point position = Control.MousePosition;
if (Properties.Settings.Default.StaysOpenWhenFocusLost &&
AsList.Any(m => m.IsMouseOn(position)))
AsList.Any(m => m.IsMouseOn()))
{
if (!keyboardInput.InUse)
{
@ -1146,22 +1201,23 @@ namespace SystemTrayMenu.Business
{
Rectangle screenBounds;
bool isCustomLocationOutsideOfScreen = false;
if (Properties.Settings.Default.AppearAtMouseLocation)
{
screenBounds = Screen.FromPoint(Cursor.Position).Bounds;
screenBounds = NativeMethods.Screen.FromPoint(NativeMethods.Screen.CursorPosition);
}
else if (Properties.Settings.Default.UseCustomLocation)
{
screenBounds = Screen.FromPoint(new Point(
screenBounds = NativeMethods.Screen.FromPoint(new Point(
Properties.Settings.Default.CustomLocationX,
Properties.Settings.Default.CustomLocationY)).Bounds;
Properties.Settings.Default.CustomLocationY));
isCustomLocationOutsideOfScreen = !screenBounds.Contains(
new Point(Properties.Settings.Default.CustomLocationX, Properties.Settings.Default.CustomLocationY));
}
else
{
screenBounds = Screen.PrimaryScreen.Bounds;
screenBounds = NativeMethods.Screen.PrimaryScreen;
}
// Only apply taskbar position change when no menu is currently open
@ -1209,17 +1265,8 @@ namespace SystemTrayMenu.Business
{
menu = list[i];
// Only last one has to be updated as all previous one were already updated in the past
if (list.Count - 1 == i)
{
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation, isCustomLocationOutsideOfScreen);
}
else
{
// workaround added also as else, because need adjust scrollbar after search
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation, isCustomLocationOutsideOfScreen);
}
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation, isCustomLocationOutsideOfScreen);
#if TODO // What is this, doesn't seem to have any effect ?
if (!Properties.Settings.Default.AppearAtTheBottomLeft &&
!Properties.Settings.Default.AppearAtMouseLocation &&
!Properties.Settings.Default.UseCustomLocation &&
@ -1230,16 +1277,17 @@ namespace SystemTrayMenu.Business
// Remember width of the initial menu as we don't want to overlap with it
if (taskbarPosition == TaskbarPosition.Left)
{
screenBounds.X += menu.Width - overlapTolerance;
screenBounds.X += (int)menu.Width - overlapTolerance;
}
screenBounds.Width -= menu.Width - overlapTolerance;
screenBounds.Width -= (int)menu.Width - overlapTolerance;
}
#endif
menuPredecessor = menu;
}
}
#if TODO
private void Menu_KeyPressCheck(object sender, KeyPressEventArgs e)
{
if (isDraggingSwipeScrolling)
@ -1247,6 +1295,7 @@ namespace SystemTrayMenu.Business
e.Handled = true;
}
}
#endif
private void Menu_SearchTextChanging()
{
@ -1293,18 +1342,18 @@ namespace SystemTrayMenu.Business
if (e is RenamedEventArgs renamedEventArgs)
{
menus[0].Invoke(() => RenameItem(renamedEventArgs));
menus[0].Dispatcher.Invoke(() => RenameItem(renamedEventArgs));
}
else
{
FileSystemEventArgs fileSystemEventArgs = (FileSystemEventArgs)e;
if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Deleted)
{
menus[0].Invoke(() => DeleteItem(e as FileSystemEventArgs));
menus[0].Dispatcher.Invoke(() => DeleteItem(e as FileSystemEventArgs));
}
else if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Created)
{
menus[0].Invoke(() => CreateItem(e as FileSystemEventArgs));
menus[0].Dispatcher.Invoke(() => CreateItem(e as FileSystemEventArgs));
}
}
}
@ -1314,6 +1363,7 @@ namespace SystemTrayMenu.Business
try
{
List<RowData> rowDatas = new();
#if TODO
DataTable dataTable = (DataTable)menus[0].GetDataGridView().DataSource;
foreach (DataRow row in dataTable.Rows)
{
@ -1343,6 +1393,7 @@ namespace SystemTrayMenu.Business
rowDatas.Add(rowData);
}
}
#endif
rowDatas = MenusHelpers.SortItems(rowDatas);
keyboardInput.ClearIsSelectedByKey();
@ -1365,7 +1416,8 @@ namespace SystemTrayMenu.Business
try
{
List<DataRow> rowsToRemove = new();
DataGridView dgv = menus[0].GetDataGridView();
#if TODO
ListView dgv = menus[0].GetDataGridView();
DataTable dataTable = (DataTable)dgv.DataSource;
foreach (DataRow row in dataTable.Rows)
{
@ -1385,6 +1437,7 @@ namespace SystemTrayMenu.Business
keyboardInput.ClearIsSelectedByKey();
dgv.DataSource = dataTable;
#endif
hideSubmenuDuringRefreshSearch = false;
menus[0].ResetHeight();
@ -1417,11 +1470,13 @@ namespace SystemTrayMenu.Business
rowData,
};
#if TODO
DataTable dataTable = (DataTable)menus[0].GetDataGridView().DataSource;
foreach (DataRow row in dataTable.Rows)
{
rowDatas.Add((RowData)row[2]);
}
#endif
rowDatas = MenusHelpers.SortItems(rowDatas);
keyboardInput.ClearIsSelectedByKey();

View file

@ -1,82 +1,85 @@
// <copyright file="Program.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu
{
using System;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
internal static class Program
{
private static bool isStartup = true;
[STAThread]
private static void Main(string[] args)
{
try
{
Log.Initialize();
Translator.Initialize();
Config.SetFolderByWindowsContextMenu(args);
Config.LoadOrSetByUser();
Config.Initialize();
if (SingleAppInstance.Initialize())
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += (sender, e) => AskUserSendError(e.Exception);
Scaling.Initialize();
FolderOptions.Initialize();
using (new App())
{
isStartup = false;
Log.WriteApplicationRuns();
Application.Run();
}
}
Config.Dispose();
}
catch (Exception ex)
{
AskUserSendError(ex);
}
finally
{
Log.Close();
}
static void AskUserSendError(Exception ex)
{
Log.Error("Application Crashed", ex);
DialogResult dialogResult = MessageBox.Show(
"A problem has been encountered and the application needs to restart. " +
"Reporting this error will help us make our product better. " +
"Press 'Yes' to open your standard email app (emailto: Markus@Hofknecht.eu). " + Environment.NewLine +
@"You can also create an issue manually here https://github.com/Hofknecht/SystemTrayMenu/issues" + Environment.NewLine +
"Press 'Cancel' to quit SystemTrayMenu.",
"SystemTrayMenu Crashed",
MessageBoxButtons.YesNoCancel);
if (dialogResult == DialogResult.Yes)
{
Log.ProcessStart("mailto:" + "markus@hofknecht.eu" +
"?subject=SystemTrayMenu Bug reported " +
Assembly.GetEntryAssembly().GetName().Version +
"&body=" + ex.ToString());
}
if (!isStartup && dialogResult != DialogResult.Cancel)
{
AppRestart.ByThreadException();
}
}
}
}
// <copyright file="Program.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu
{
using System;
using System.Reflection;
using System.Windows;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.FormsExtensions;
internal static class Program
{
private static bool isStartup = true;
[STAThread]
private static void Main(string[] args)
{
try
{
Log.Initialize();
Translator.Initialize();
Config.SetFolderByWindowsContextMenu(args);
Config.LoadOrSetByUser();
Config.Initialize();
if (SingleAppInstance.Initialize())
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += (sender, args)
=> AskUserSendError((Exception)args.ExceptionObject);
Scaling.Initialize();
FolderOptions.Initialize();
using (App app = new App())
{
app.InitializeComponent();
isStartup = false;
Log.WriteApplicationRuns();
app.Run();
}
}
Config.Dispose();
}
catch (Exception ex)
{
AskUserSendError(ex);
}
finally
{
Log.Close();
}
static void AskUserSendError(Exception ex)
{
Log.Error("Application Crashed", ex);
MessageBoxResult dialogResult = MessageBox.Show(
"A problem has been encountered and the application needs to restart. " +
"Reporting this error will help us make our product better. " +
"Press 'Yes' to open your standard email app (emailto: Markus@Hofknecht.eu). " + Environment.NewLine +
@"You can also create an issue manually here https://github.com/Hofknecht/SystemTrayMenu/issues" + Environment.NewLine +
"Press 'Cancel' to quit SystemTrayMenu.",
"SystemTrayMenu Crashed",
MessageBoxButton.YesNoCancel);
if (dialogResult == MessageBoxResult.Yes)
{
Log.ProcessStart("mailto:" + "markus@hofknecht.eu" +
"?subject=SystemTrayMenu Bug reported " +
Assembly.GetEntryAssembly().GetName().Version +
"&body=" + ex.ToString());
}
if (!isStartup && dialogResult != MessageBoxResult.Cancel)
{
AppRestart.ByThreadException();
}
}
}
}
}

View file

@ -4,25 +4,25 @@
namespace SystemTrayMenu.Handler
{
using System;
using System;
using System.Windows.Threading;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
internal class WaitLeave : IDisposable
{
private readonly Timer timerLeaveCheck = new();
private readonly DispatcherTimer timerLeaveCheck = new();
public WaitLeave(int timeUntilTriggered)
{
timerLeaveCheck.Interval = timeUntilTriggered;
timerLeaveCheck.Interval = TimeSpan.FromMilliseconds(timeUntilTriggered);
timerLeaveCheck.Tick += TimerLeaveCheckTick;
}
public event EventHandlerEmpty LeaveTriggered;
public event Action LeaveTriggered;
public void Dispose()
{
timerLeaveCheck.Dispose();
{
timerLeaveCheck.Stop();
}
internal void Start()

View file

@ -1,219 +1,231 @@
// <copyright file="WaitToLoadMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Handler
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using 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 = Properties.Settings.Default.TimeUntilOpens;
timerStartLoad.Tick += WaitStartLoad_Tick;
}
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event EventHandlerEmpty StopLoadMenu;
internal event Action<DataGridView, int> MouseEnterOk;
internal bool MouseActive { get; set; }
public void Dispose()
{
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(int rowIndex, DataGridView dgv)
{
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;
}
}
}
}
// <copyright file="WaitToLoadMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Handler
{
using System;
using System.Data;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using ListView = System.Windows.Controls.ListView;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class WaitToLoadMenu : IDisposable
{
private readonly DispatcherTimer timerStartLoad = new();
private ListView dgv;
private int rowIndex;
private ListView dgvTmp;
private int rowIndexTmp;
private int mouseMoveEvents;
private DateTime dateTimeLastMouseMoveEvent = DateTime.Now;
private bool checkForMouseActive = true;
internal WaitToLoadMenu()
{
timerStartLoad.Interval = TimeSpan.FromMilliseconds(Properties.Settings.Default.TimeUntilOpens);
timerStartLoad.Tick += WaitStartLoad_Tick;
}
internal event Action<RowData> StartLoadMenu;
internal event Action<int> CloseMenu;
internal event Action StopLoadMenu;
internal event Action<ListView, int> MouseEnterOk;
internal bool MouseActive { get; set; }
public void Dispose()
{
timerStartLoad.Stop();
#if TODO
dgv?.Dispose();
dgvTmp?.Dispose();
#endif
}
internal void MouseEnter(object sender, int rowIndex)
{
ListView dgv = (ListView)sender;
if (MouseActive)
{
if (dgv.Items.Count > rowIndex)
{
MouseEnterOk(dgv, rowIndex);
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
checkForMouseActive = true;
SetData(dgv, rowIndex);
timerStartLoad.Start();
}
}
else
{
dgvTmp = dgv;
rowIndexTmp = rowIndex;
}
}
internal void RowSelected(ListView dgv, int rowIndex)
{
if (dgv.Items.Count > rowIndex)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
SetData(dgv, rowIndex);
MouseActive = false;
checkForMouseActive = false;
timerStartLoad.Start();
}
}
internal void MouseLeave(object sender, int rowIndex)
{
if (MouseActive)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData((ListView)sender, rowIndex);
}
}
internal void RowDeselected(int rowIndex, ListView dgv)
{
timerStartLoad.Stop();
StopLoadMenu?.Invoke();
ResetData(dgv, rowIndex);
MouseActive = false;
}
internal void ClickOpensInstantly(ListView dgv, int rowIndex)
{
if (dgv.Items.Count > rowIndex)
{
timerStartLoad.Stop();
SetData(dgv, rowIndex);
MouseActive = true;
checkForMouseActive = false;
CallOpenMenuNow();
}
}
internal void EnterOpensInstantly(ListView dgv, int rowIndex)
{
if (dgv.Items.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
#if TODO
&& !dgvTmp.IsDisposed
#endif
)
{
MouseEnter(dgvTmp, 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.Items.Count > rowIndex)
{
RowData rowData = ((Menu.ListViewItemData)dgv.Items[rowIndex]).data;
Menu menu = (Menu)dgv.GetParentWindow();
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(ListView dgv, int rowIndex)
{
dgvTmp = null;
this.dgv = dgv;
this.rowIndex = rowIndex;
#if TODO
RowData rowData = (RowData)dgv.Items[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = true;
}
dgv.Items[rowIndex].Selected = false;
dgv.Items[rowIndex].Selected = true;
#endif
}
private void ResetData(ListView dgv, int rowIndex)
{
if (dgv != null && dgv.Items.Count > rowIndex)
{
#if TODO
RowData rowData = (RowData)dgv.Items[rowIndex].Cells[2].Value;
if (rowData != null)
{
rowData.IsSelected = false;
rowData.IsClicking = false;
dgv.Items[rowIndex].Selected = false;
this.dgv = null;
this.rowIndex = 0;
}
#endif
}
}
}
}

View file

@ -4,8 +4,10 @@
namespace SystemTrayMenu
{
using System.Drawing;
using System.Drawing;
using System.Windows.Media;
using Color = System.Drawing.Color;
internal static class AppColors
{
public static Color Arrow { get; internal set; }
@ -90,6 +92,11 @@ namespace SystemTrayMenu
public static Color Icons { get; set; }
public static Color DarkModeIcons { get; set; }
public static Color DarkModeIcons { get; set; }
public static SolidColorBrush ToSolidColorBrush(this Color color)
{
return new SolidColorBrush(System.Windows.Media.Color.FromArgb(color.A, color.R, color.G, color.B));
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,302 +1,305 @@
// <copyright file="RowData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DataClasses
{
using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using 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 = Properties.Settings.Default.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 = Properties.Settings.Default.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 (Properties.Settings.Default.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 (Properties.Settings.Default.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
}
}
internal void DoubleClick(MouseEventArgs e, out bool toCloseByDoubleClick)
{
IsClicking = false;
toCloseByDoubleClick = false;
if (!Properties.Settings.Default.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (!Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.Button == MouseButtons.Left))
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.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 (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByOpenItem = true;
}
}
}
}
}
// <copyright file="RowData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DataClasses
{
using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.IconReader;
using Menu = SystemTrayMenu.UserInterface.Menu;
internal class RowData
{
private static DateTime contextMenuClosed;
/// <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 = Properties.Settings.Default.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 = Properties.Settings.Default.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 (Properties.Settings.Default.ResolveLinksToFolders)
{
ContainsMenu |= IsLinkToFolder;
}
IsMainMenu = Level == 0;
}
catch (Exception ex)
{
Log.Warn($"path:'{path}'", ex);
}
}
internal Icon Icon { get; private set; }
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; }
#if TODO // WPF REMOVE?
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;
}
#endif
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(ListView dgv, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
IsClicking = true;
}
if (e != null &&
e.RightButton == MouseButtonState.Pressed &&
FileInfo != null &&
dgv != null &&
dgv.Items.Count > RowIndex &&
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
{
IsContextMenuOpen = true;
ShellContextMenu ctxMnu = new();
Window window = dgv.GetParentWindow();
var position = Mouse.GetPosition(window);
position.Offset(window.Left, window.Top);
if (ContainsMenu)
{
DirectoryInfo[] dir = new DirectoryInfo[1];
dir[0] = new DirectoryInfo(Path);
ctxMnu.ShowContextMenu(dir, position);
TriggerFileWatcherChangeWorkaround();
}
else
{
FileInfo[] arrFI = new FileInfo[1];
arrFI[0] = FileInfo;
ctxMnu.ShowContextMenu(arrFI, position);
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 (Properties.Settings.Default.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed))
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
}
}
internal void DoubleClick(MouseButtonEventArgs e, out bool toCloseByDoubleClick)
{
IsClicking = false;
toCloseByDoubleClick = false;
if (!Properties.Settings.Default.OpenItemWithOneClick)
{
OpenItem(e, ref toCloseByDoubleClick);
}
if (!Properties.Settings.Default.OpenDirectoryWithOneClick &&
ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed))
{
Log.ProcessStart(Path);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByDoubleClick = true;
}
}
}
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
{
if (!ContainsMenu &&
(e == null || e.LeftButton == MouseButtonState.Pressed))
{
ProcessStarted = true;
string workingDirectory = System.IO.Path.GetDirectoryName(ResolvedPath);
Log.ProcessStart(Path, string.Empty, false, workingDirectory, true, ResolvedPath);
if (!Properties.Settings.Default.StaysOpenWhenItemClicked)
{
toCloseByOpenItem = true;
}
}
}
}
}

View file

@ -1,99 +1,102 @@
// <copyright file="DgvMouseRow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace 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 += Elapsed;
void Elapsed(object sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
}
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.Dispose();
dgv?.Dispose();
}
}
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);
}
}
// <copyright file="DgvMouseRow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
#nullable enable
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Threading;
public class DgvMouseRow<T> : IDisposable
where T : notnull
{
private readonly DispatcherTimer timerRaiseRowMouseLeave = new DispatcherTimer(DispatcherPriority.Input, Dispatcher.CurrentDispatcher);
private T? senderObject;
private int? senderIndex;
internal DgvMouseRow()
{
timerRaiseRowMouseLeave.Interval = TimeSpan.FromMilliseconds(200);
timerRaiseRowMouseLeave.Tick += Elapsed;
void Elapsed(object? sender, EventArgs e)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
}
internal event Action<T, int>? RowMouseEnter;
internal event Action<T, int>? RowMouseLeave;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
internal void CellMouseEnter(T sender, int index)
{
if (!sender.Equals(senderObject) || index != senderIndex)
{
if (timerRaiseRowMouseLeave.IsEnabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
TriggerRowMouseEnter(sender, index);
}
else
{
timerRaiseRowMouseLeave.Stop();
}
senderObject = sender;
senderIndex = index;
}
internal void CellMouseLeave(T sender, int index)
{
timerRaiseRowMouseLeave.Start();
}
internal void MouseLeave(object sender, EventArgs e)
{
if (timerRaiseRowMouseLeave.IsEnabled)
{
timerRaiseRowMouseLeave.Stop();
TriggerRowMouseLeave();
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
timerRaiseRowMouseLeave.Stop();
#if TODO
senderObject?.Dispose();
#endif
}
}
private void TriggerRowMouseLeave()
{
if (senderObject != null && senderIndex.HasValue)
{
RowMouseLeave?.Invoke(senderObject, senderIndex.Value);
}
senderObject = default(T);
senderIndex = null;
}
private void TriggerRowMouseEnter(T sender, int rowIndex)
{
RowMouseEnter?.Invoke(sender, rowIndex);
}
}
}

View file

@ -1,190 +1,190 @@
// <copyright file="DragDropHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using 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 = Properties.Settings.Default.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;
}
}
}
// <copyright file="DragDropHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Windows;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using 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.Effects = 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 = Properties.Settings.Default.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

@ -4,8 +4,8 @@
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using System;
using System.Windows.Threading;
using SystemTrayMenu.Utilities;
public class Fading : IDisposable
@ -20,20 +20,20 @@ namespace SystemTrayMenu.Helper
private const double Shown = 1.00;
private const double ShownMinus = 0.80; // Shown - StepIn
private readonly Timer timer = new();
private readonly DispatcherTimer timer = new(DispatcherPriority.Render);
private FadingState state = FadingState.Idle;
private double opacity;
private bool visible;
internal Fading()
{
timer.Interval = Interval100FPS;
timer.Interval = TimeSpan.FromMilliseconds(Interval100FPS);
timer.Tick += (sender, e) => FadeStep();
}
internal event EventHandlerEmpty Hide;
internal event Action Hide;
internal event EventHandlerEmpty Show;
internal event Action Show;
internal event EventHandler<double> ChangeOpacity;
@ -62,7 +62,7 @@ namespace SystemTrayMenu.Helper
{
if (disposing)
{
timer.Dispose();
timer.Stop();
}
}

View file

@ -1,209 +1,215 @@
// <copyright file="JoystickHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace 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 (Properties.Settings.Default.SupportGamepad)
{
timerReadJoystick.Start();
}
}
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?.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();
}
}
}
}
// <copyright file="JoystickHelper.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helpers
{
using System;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Reflection.Metadata;
using System.Threading;
using SharpDX.DirectInput;
using Key = System.Windows.Input.Key;
public class JoystickHelper : IDisposable
{
private readonly System.Timers.Timer timerReadJoystick = new();
private readonly object lockRead = new();
private Joystick joystick;
private Key pressingKey;
private int pressingKeyCounter;
private bool joystickHelperEnabled;
public JoystickHelper()
{
timerReadJoystick.Interval = 80;
timerReadJoystick.Elapsed += ReadJoystickLoop;
timerReadJoystick.Enabled = false;
if (Properties.Settings.Default.SupportGamepad)
{
timerReadJoystick.Start();
}
}
~JoystickHelper() // the finalizer
{
Dispose(false);
}
public event Action<Key> 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 Key ReadKeyFromState(JoystickUpdate state)
{
Key keys = Key.None;
switch (state.Offset)
{
case JoystickOffset.PointOfViewControllers0:
switch (state.Value)
{
case 0:
keys = Key.Up;
break;
case 9000:
keys = Key.Right;
break;
case 18000:
keys = Key.Down;
break;
case 27000:
keys = Key.Left;
break;
default:
break;
}
break;
case JoystickOffset.Buttons0:
if (state.Value == 128)
{
keys = Key.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 = Key.None;
pressingKeyCounter = 0;
continue;
}
Key key = ReadKeyFromState(state);
if (key != Key.None)
{
KeyPressed?.Invoke(key);
if (state.Offset == JoystickOffset.PointOfViewControllers0)
{
pressingKeyCounter = 0;
pressingKey = key;
}
}
}
if (pressingKey != Key.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

@ -4,17 +4,17 @@
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using System;
using System.Windows.Input;
/// <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;
private readonly Key key;
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key)
internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Key key)
{
Modifier = modifier;
this.key = key;
@ -22,6 +22,6 @@ namespace SystemTrayMenu.Helper
internal KeyboardHookModifierKeys Modifier { get; }
internal Keys Key => key;
internal Key Key => key;
}
}

View file

@ -1,160 +1,157 @@
// <copyright file="KeyboardHook.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.UserInterface.HotkeyTextboxControl;
using SystemTrayMenu.Utilities;
/// <summary>
/// The enumeration of possible modifiers.
/// </summary>
[Flags]
internal 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 += (sender, e) => KeyPressed?.Invoke(this, e);
}
/// <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--)
{
DllImports.NativeMethods.User32UnregisterHotKey(window.Handle, i);
}
// dispose the inner native window.
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 = Properties.Settings.Default.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(
Properties.Settings.Default.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 RegisterHotKey(uint modifier, Keys key)
{
currentId += 1;
if (!DllImports.NativeMethods.User32RegisterHotKey(
window.Handle, currentId, modifier, (uint)key))
{
throw new InvalidOperationException(
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));
}
}
}
}
}
// <copyright file="KeyboardHook.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Windows.Input;
using SystemTrayMenu.UserInterface.HotkeyTextboxControl;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.FormsExtensions;
/// <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--)
{
DllImports.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(Key key)
{
uint keyModifiersNone = 0;
RegisterHotKey(keyModifiersNone, key);
}
internal void RegisterHotKey()
{
KeyboardHookModifierKeys modifiers = KeyboardHookModifierKeys.None;
string modifiersString = Properties.Settings.Default.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;
}
}
#if TODO //HOTKEY
RegisterHotKey(
modifiers,
HotkeyControl.HotkeyFromString(
Properties.Settings.Default.HotKey));
#endif
}
/// <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, Key key)
{
RegisterHotKey((uint)modifier, key);
}
private void Window_KeyPressed(object sender, KeyPressedEventArgs e)
{
KeyPressed?.Invoke(this, e);
}
private void RegisterHotKey(uint modifier, Key key)
{
currentId += 1;
if (!DllImports.NativeMethods.User32RegisterHotKey(
window.Handle, currentId, modifier, (uint)key))
{
throw new InvalidOperationException(
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 event EventHandler<KeyPressedEventArgs> KeyPressed;
/// <summary>
/// Overridden to get the notifications.
/// </summary>
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// check if we got a hot key pressed.
if (msg == WmHotkey)
{
// get the keys.
Key key = (Key)(((int)lParam >> 16) & 0xFFFF);
KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)lParam & 0xFFFF);
// invoke the event to notify the parent.
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
}
handled = false;
return IntPtr.Zero;
}
}
}
}

View file

@ -1,68 +0,0 @@
// <copyright file="BringWindowToTop.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SwRestore = 9;
public static void ForceForegroundWindow(IntPtr hWnd)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const int SW_SHOW = 5;
int cmdShow = SW_SHOW;
if (IsIconic(hWnd))
{
cmdShow = SwRestore;
}
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool BringWindowToTop(IntPtr hWnd);
}
}

View file

@ -1,40 +0,0 @@
// <copyright file="CreateRoundRectRgn.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static bool GetRegionRoundCorners(int width, int height, int widthEllipse, int heightEllipse, out System.Drawing.Region region)
{
bool success = false;
region = null;
IntPtr handle = CreateRoundRectRgn(0, 0, width, height, widthEllipse, heightEllipse);
if (handle != IntPtr.Zero)
{
region = System.Drawing.Region.FromHrgn(handle);
_ = DeleteObject(handle);
success = true;
}
return success;
}
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateRoundRectRgn(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // width of ellipse
int nHeightEllipse); // height of ellipse
}
}

145
NativeDllImport/Screen.cs Normal file
View file

@ -0,0 +1,145 @@
// <copyright file="Screen.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.DllImports
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static class Screen
{
private static Point LastCursorPosition = new Point(0, 0);
private static List<Rectangle>? screens;
public static List<Rectangle> Screens
{
get
{
if ((screens == null) || (screens.Count == 0))
{
FetchScreens();
}
if ((screens == null) || (screens.Count == 0))
{
return new()
{
new Rectangle(0, 0, 800, 600),
};
}
return screens;
}
}
public static Rectangle PrimaryScreen => Screens[0];
public static Point CursorPosition
{
get
{
NativeMethods.POINT lpPoint;
if (NativeMethods.GetCursorPos(out lpPoint))
{
LastCursorPosition = new(lpPoint.X, lpPoint.Y);
}
return LastCursorPosition;
}
}
public static Rectangle FromPoint(Point pt)
{
foreach (Rectangle screen in Screens)
{
if (screen.Contains(pt))
{
return screen;
}
}
// Use primary screen as fallback
return Screens[0];
}
internal static void FetchScreens()
{
var backup = screens;
screens = new();
if (!NativeMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumCallback, IntPtr.Zero))
{
screens = backup;
}
}
private static bool MonitorEnumCallback(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeMethods.RECT lprcMonitor, IntPtr dwData)
{
try
{
screens!.Add(new()
{
X = lprcMonitor.left,
Y = lprcMonitor.top,
Width = lprcMonitor.right - lprcMonitor.left,
Height = lprcMonitor.bottom - lprcMonitor.top,
});
}
catch
{
// Catch everything as this callback runs within a native context
}
return true;
}
private class NativeMethods
{
public delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors .
/// </summary>
[SupportedOSPlatform("windows")]
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos .
/// </summary>
[SupportedOSPlatform("windows")]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetCursorPos(out POINT lpPoint);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct POINT
{
public int X;
public int Y;
}
}
}
}
}

View file

@ -1,46 +0,0 @@
// <copyright file="ShowInactiveTopmost.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System.Runtime.InteropServices;
using System.Windows.Forms;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
public static void User32ShowInactiveTopmost(Form form)
{
if (form != null)
{
_ = ShowWindow(form.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(
form.Handle.ToInt32(),
HWND_TOPMOST,
form.Left,
form.Top,
form.Width,
form.Height,
SWP_NOACTIVATE);
}
}
[DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
}
}

View file

@ -1,19 +1,48 @@
// <copyright file="ShowWindow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
}
// <copyright file="ShowWindow.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.DllImports
{
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Windows;
using System.Windows.Interop;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int GWL_EXSTYLE = -20;
internal static void HideFromAltTab(Window window)
{
WindowInteropHelper wndHelper = new WindowInteropHelper(window);
int exStyle = (int)GetWindowLongPtr(wndHelper.Handle, GWL_EXSTYLE);
exStyle |= WS_EX_TOOLWINDOW; // do not show when user presses alt + tab
SetWindowLongPtr(wndHelper.Handle, GWL_EXSTYLE, (IntPtr)exStyle);
}
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongptrw .
/// </summary>
[SupportedOSPlatform("windows")]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex);
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlongptrw .
/// </summary>
[SupportedOSPlatform("windows")]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
}
}

View file

@ -39,5 +39,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.3.1.7")]
[assembly: AssemblyFileVersion("1.3.1.7")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]

View file

@ -13,7 +13,7 @@ namespace SystemTrayMenu.Properties
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{

View file

@ -240,7 +240,7 @@ Special thanks to our productive contibutors!
Thanks for ideas, reporting issues and contributing!
#462 [Mario Sedlmayr](https://github.com/verdammt89x),
#462 [verdammt89x](https://github.com/verdammt89x),
#123 [Mordecai00](https://github.com/Mordecai00),
#125 [Holgermh](https://github.com/Holgermh),
#135 #153 #154 #164 [jakkaas](https://github.com/jakkaas),

View file

@ -2,10 +2,9 @@
<PropertyGroup>
<TargetFramework>net6.0-windows10.0.22000.0</TargetFramework>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>True</UseWPF>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<OutputType>WinExe</OutputType>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@ -19,7 +18,6 @@
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>true</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Platforms>x64;x86;AnyCPU</Platforms>
<Configurations>Debug;Release;ReleasePackage</Configurations>
@ -105,6 +103,18 @@
<Optimize>True</Optimize>
<NoWarn>1701;1702;WFAC010;MSB3061</NoWarn>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Helpers\Updater\GitHubUpdate.cs" />
<Compile Remove="UserInterface\CustomScrollbar\CustomScrollbar.cs" />
<Compile Remove="UserInterface\CustomScrollbar\ScrollbarControlDesigner.cs" />
<Compile Remove="UserInterface\HotkeyTextboxControl\HotkeyControl.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="UserInterface\Menu.resx" />
</ItemGroup>
<ItemGroup>
<None Remove="Resources\SystemTrayMenu.png" />
</ItemGroup>
<ItemGroup>
<Reference Include="Clearcove.Logging, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@ -122,34 +132,23 @@
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Update="UserInterface\AboutBox.Designer.cs">
<DependentUpon>AboutBox.cs</DependentUpon>
</Compile>
<Compile Update="UserInterface\CustomScrollbar\CustomScrollbar.cs" />
<Compile Update="UserInterface\SettingsForm.Designer.cs">
<DependentUpon>SettingsForm.cs</DependentUpon>
</Compile>
<EmbeddedResource Update="UserInterface\AboutBox.resx">
<DependentUpon>AboutBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="UserInterface\SettingsForm.resx">
<DependentUpon>SettingsForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="UserInterface\Menu.resx">
<DependentUpon>Menu.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Helpers\Updater\GitHubUpdate.cs" />
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="UserInterface\CustomScrollbar\CustomScrollbar.cs" />
<None Include="UserInterface\CustomScrollbar\ScrollbarControlDesigner.cs" />
<None Include="UserInterface\HotkeyTextboxControl\HotkeyControl.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\SystemTrayMenu.ico" />
<EmbeddedResource Include="Resources\SystemTrayMenu.png" />
</ItemGroup>
<ItemGroup>
<COMReference Include="IWshRuntimeLibrary">
@ -171,20 +170,9 @@
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<PackageReference Include="H.InputSimulator" Version="1.3.0" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@ -228,6 +216,32 @@ EXIT 0</PreBuildEvent>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Update="Microsoft.WindowsDesktop.App;Microsoft.WindowsDesktop.App.WPF;Microsoft.WindowsDesktop.App.WindowsForms" TargetingPackVersion="6.0.0" />
<FrameworkReference Update="Microsoft.WindowsDesktop.App;Microsoft.WindowsDesktop.App.WPF" TargetingPackVersion="6.0.0" />
</ItemGroup>
<!-- it seems only obj clean and then opening visual studio helps -->
<!-- NOT TESTED: Microsoft.NET.Sdk.WindowsDesktop -->
<!-- Workaround: Clear C:\Users\Peter K\AppData\Local\Microsoft\VisualStudio\14.0\ComponentModelCache (and bin and obj) -->
<!-- Workaround for XAML compiler issue https://github.com/dotnet/wpf/issues/4299
<UsingTask TaskName="Sleep" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Delay ParameterType="System.Int32" Required="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
<![CDATA[
System.Threading.Thread.Sleep(this.Delay);
]]>
</Code>
</Task>
</UsingTask>
<Target Name="WaitForFiles" BeforeTargets="CoreCompile">
<PropertyGroup>
<WaitTime>5000</WaitTime>
</PropertyGroup>
<Message Text="Waiting for $(WaitTime)ms" Importance="high" />
<Sleep Delay="$(WaitTime)"/>
</Target>
-->
</Project>

View file

@ -1,510 +0,0 @@
namespace SystemTrayMenu.UserInterface
{
internal partial class AboutBox
{
/// <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(AboutBox));
this.buttonDetails = new System.Windows.Forms.Button();
this.ImagePictureBox = new System.Windows.Forms.PictureBox();
this.AppDateLabel = new System.Windows.Forms.Label();
this.buttonSystemInfo = new System.Windows.Forms.Button();
this.AppCopyrightLabel = new System.Windows.Forms.Label();
this.AppVersionLabel = new System.Windows.Forms.Label();
this.AppDescriptionLabel = new System.Windows.Forms.Label();
this.GroupBox1 = new System.Windows.Forms.GroupBox();
this.AppTitleLabel = new System.Windows.Forms.Label();
this.buttonOk = new System.Windows.Forms.Button();
this.MoreRichTextBox = new System.Windows.Forms.RichTextBox();
this.TabPanelDetails = new System.Windows.Forms.TabControl();
this.TabPageApplication = new System.Windows.Forms.TabPage();
this.AppInfoListView = new System.Windows.Forms.ListView();
this.colKey = new System.Windows.Forms.ColumnHeader();
this.colValue = new System.Windows.Forms.ColumnHeader();
this.TabPageAssemblies = new System.Windows.Forms.TabPage();
this.AssemblyInfoListView = new System.Windows.Forms.ListView();
this.colAssemblyName = new System.Windows.Forms.ColumnHeader();
this.colAssemblyVersion = new System.Windows.Forms.ColumnHeader();
this.colAssemblyBuilt = new System.Windows.Forms.ColumnHeader();
this.colAssemblyCodeBase = new System.Windows.Forms.ColumnHeader();
this.TabPageAssemblyDetails = new System.Windows.Forms.TabPage();
this.AssemblyDetailsListView = new System.Windows.Forms.ListView();
this.ColumnHeader1 = new System.Windows.Forms.ColumnHeader();
this.ColumnHeader2 = new System.Windows.Forms.ColumnHeader();
this.AssemblyNamesComboBox = new System.Windows.Forms.ComboBox();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
((System.ComponentModel.ISupportInitialize)(this.ImagePictureBox)).BeginInit();
this.TabPanelDetails.SuspendLayout();
this.TabPageApplication.SuspendLayout();
this.TabPageAssemblies.SuspendLayout();
this.TabPageAssemblyDetails.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.tableLayoutPanel3.SuspendLayout();
this.SuspendLayout();
//
// buttonDetails
//
this.buttonDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonDetails.AutoSize = true;
this.buttonDetails.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.buttonDetails.Location = new System.Drawing.Point(88, 3);
this.buttonDetails.MinimumSize = new System.Drawing.Size(76, 23);
this.buttonDetails.Name = "buttonDetails";
this.buttonDetails.Size = new System.Drawing.Size(76, 25);
this.buttonDetails.TabIndex = 25;
this.buttonDetails.Text = "Details";
this.buttonDetails.Click += new System.EventHandler(this.DetailsButton_Click);
//
// ImagePictureBox
//
this.ImagePictureBox.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("ImagePictureBox.BackgroundImage")));
this.ImagePictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.ImagePictureBox.Location = new System.Drawing.Point(3, 3);
this.ImagePictureBox.Name = "ImagePictureBox";
this.ImagePictureBox.Size = new System.Drawing.Size(36, 36);
this.ImagePictureBox.TabIndex = 24;
this.ImagePictureBox.TabStop = false;
//
// AppDateLabel
//
this.AppDateLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AppDateLabel.AutoSize = true;
this.AppDateLabel.Location = new System.Drawing.Point(3, 82);
this.AppDateLabel.Margin = new System.Windows.Forms.Padding(3);
this.AppDateLabel.Name = "AppDateLabel";
this.AppDateLabel.Size = new System.Drawing.Size(383, 15);
this.AppDateLabel.TabIndex = 23;
this.AppDateLabel.Text = "Built on %builddate%";
//
// buttonSystemInfo
//
this.buttonSystemInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonSystemInfo.AutoSize = true;
this.buttonSystemInfo.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.buttonSystemInfo.Location = new System.Drawing.Point(3, 3);
this.buttonSystemInfo.MinimumSize = new System.Drawing.Size(76, 23);
this.buttonSystemInfo.Name = "buttonSystemInfo";
this.buttonSystemInfo.Size = new System.Drawing.Size(79, 25);
this.buttonSystemInfo.TabIndex = 22;
this.buttonSystemInfo.Text = "System Info";
this.buttonSystemInfo.Visible = false;
this.buttonSystemInfo.Click += new System.EventHandler(this.SysInfoButton_Click);
//
// AppCopyrightLabel
//
this.AppCopyrightLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AppCopyrightLabel.AutoSize = true;
this.AppCopyrightLabel.Location = new System.Drawing.Point(3, 103);
this.AppCopyrightLabel.Margin = new System.Windows.Forms.Padding(3);
this.AppCopyrightLabel.Name = "AppCopyrightLabel";
this.AppCopyrightLabel.Size = new System.Drawing.Size(383, 15);
this.AppCopyrightLabel.TabIndex = 21;
this.AppCopyrightLabel.Text = "Copyright © %year%, %company%";
//
// AppVersionLabel
//
this.AppVersionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AppVersionLabel.AutoSize = true;
this.AppVersionLabel.Location = new System.Drawing.Point(3, 61);
this.AppVersionLabel.Margin = new System.Windows.Forms.Padding(3);
this.AppVersionLabel.Name = "AppVersionLabel";
this.AppVersionLabel.Size = new System.Drawing.Size(383, 15);
this.AppVersionLabel.TabIndex = 20;
this.AppVersionLabel.Text = "Version %version%";
//
// AppDescriptionLabel
//
this.AppDescriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AppDescriptionLabel.AutoSize = true;
this.AppDescriptionLabel.Location = new System.Drawing.Point(3, 24);
this.AppDescriptionLabel.Margin = new System.Windows.Forms.Padding(3);
this.AppDescriptionLabel.Name = "AppDescriptionLabel";
this.AppDescriptionLabel.Size = new System.Drawing.Size(86, 15);
this.AppDescriptionLabel.TabIndex = 19;
this.AppDescriptionLabel.Text = "%description%";
//
// GroupBox1
//
this.GroupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.GroupBox1.Location = new System.Drawing.Point(3, 53);
this.GroupBox1.Name = "GroupBox1";
this.GroupBox1.Size = new System.Drawing.Size(383, 2);
this.GroupBox1.TabIndex = 18;
this.GroupBox1.TabStop = false;
this.GroupBox1.Text = "GroupBox1";
//
// AppTitleLabel
//
this.AppTitleLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.AppTitleLabel.AutoSize = true;
this.AppTitleLabel.Location = new System.Drawing.Point(3, 3);
this.AppTitleLabel.Margin = new System.Windows.Forms.Padding(3);
this.AppTitleLabel.Name = "AppTitleLabel";
this.AppTitleLabel.Size = new System.Drawing.Size(86, 15);
this.AppTitleLabel.TabIndex = 17;
this.AppTitleLabel.Text = "%title%";
//
// buttonOk
//
this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonOk.AutoSize = true;
this.buttonOk.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonOk.Location = new System.Drawing.Point(170, 3);
this.buttonOk.MinimumSize = new System.Drawing.Size(76, 23);
this.buttonOk.Name = "buttonOk";
this.buttonOk.Size = new System.Drawing.Size(76, 25);
this.buttonOk.TabIndex = 16;
this.buttonOk.Text = "OK";
//
// MoreRichTextBox
//
this.MoreRichTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MoreRichTextBox.BackColor = System.Drawing.SystemColors.ControlLight;
this.MoreRichTextBox.Location = new System.Drawing.Point(3, 124);
this.MoreRichTextBox.Name = "MoreRichTextBox";
this.MoreRichTextBox.ReadOnly = true;
this.MoreRichTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
this.MoreRichTextBox.Size = new System.Drawing.Size(383, 122);
this.MoreRichTextBox.TabIndex = 26;
this.MoreRichTextBox.Text = "%product% is %copyright%, %trademark%";
this.MoreRichTextBox.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.MoreRichTextBox_LinkClicked);
//
// TabPanelDetails
//
this.TabPanelDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.TabPanelDetails.Controls.Add(this.TabPageApplication);
this.TabPanelDetails.Controls.Add(this.TabPageAssemblies);
this.TabPanelDetails.Controls.Add(this.TabPageAssemblyDetails);
this.TabPanelDetails.Location = new System.Drawing.Point(3, 252);
this.TabPanelDetails.Name = "TabPanelDetails";
this.TabPanelDetails.SelectedIndex = 0;
this.TabPanelDetails.Size = new System.Drawing.Size(383, 149);
this.TabPanelDetails.TabIndex = 27;
this.TabPanelDetails.Visible = false;
this.TabPanelDetails.SelectedIndexChanged += new System.EventHandler(this.TabPanelDetails_SelectedIndexChanged);
//
// TabPageApplication
//
this.TabPageApplication.Controls.Add(this.AppInfoListView);
this.TabPageApplication.Location = new System.Drawing.Point(4, 24);
this.TabPageApplication.Name = "TabPageApplication";
this.TabPageApplication.Size = new System.Drawing.Size(375, 121);
this.TabPageApplication.TabIndex = 0;
this.TabPageApplication.Text = "Application";
//
// AppInfoListView
//
this.AppInfoListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.colKey,
this.colValue});
this.AppInfoListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.AppInfoListView.FullRowSelect = true;
this.AppInfoListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.AppInfoListView.Location = new System.Drawing.Point(0, 0);
this.AppInfoListView.Name = "AppInfoListView";
this.AppInfoListView.Size = new System.Drawing.Size(375, 121);
this.AppInfoListView.TabIndex = 16;
this.AppInfoListView.UseCompatibleStateImageBehavior = false;
this.AppInfoListView.View = System.Windows.Forms.View.Details;
//
// colKey
//
this.colKey.Text = "Application Key";
this.colKey.Width = 120;
//
// colValue
//
this.colValue.Text = "Value";
this.colValue.Width = 700;
//
// TabPageAssemblies
//
this.TabPageAssemblies.Controls.Add(this.AssemblyInfoListView);
this.TabPageAssemblies.Location = new System.Drawing.Point(4, 24);
this.TabPageAssemblies.Name = "TabPageAssemblies";
this.TabPageAssemblies.Size = new System.Drawing.Size(375, 109);
this.TabPageAssemblies.TabIndex = 1;
this.TabPageAssemblies.Text = "Assemblies";
//
// AssemblyInfoListView
//
this.AssemblyInfoListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.colAssemblyName,
this.colAssemblyVersion,
this.colAssemblyBuilt,
this.colAssemblyCodeBase});
this.AssemblyInfoListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.AssemblyInfoListView.FullRowSelect = true;
this.AssemblyInfoListView.Location = new System.Drawing.Point(0, 0);
this.AssemblyInfoListView.MultiSelect = false;
this.AssemblyInfoListView.Name = "AssemblyInfoListView";
this.AssemblyInfoListView.Size = new System.Drawing.Size(375, 109);
this.AssemblyInfoListView.Sorting = System.Windows.Forms.SortOrder.Ascending;
this.AssemblyInfoListView.TabIndex = 13;
this.AssemblyInfoListView.UseCompatibleStateImageBehavior = false;
this.AssemblyInfoListView.View = System.Windows.Forms.View.Details;
this.AssemblyInfoListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.AssemblyInfoListView_ColumnClick);
this.AssemblyInfoListView.DoubleClick += new System.EventHandler(this.AssemblyInfoListView_DoubleClick);
//
// colAssemblyName
//
this.colAssemblyName.Text = "Assembly";
this.colAssemblyName.Width = 123;
//
// colAssemblyVersion
//
this.colAssemblyVersion.Text = "Version";
this.colAssemblyVersion.Width = 100;
//
// colAssemblyBuilt
//
this.colAssemblyBuilt.Text = "Built";
this.colAssemblyBuilt.Width = 130;
//
// colAssemblyCodeBase
//
this.colAssemblyCodeBase.Text = "CodeBase";
this.colAssemblyCodeBase.Width = 750;
//
// TabPageAssemblyDetails
//
this.TabPageAssemblyDetails.Controls.Add(this.AssemblyDetailsListView);
this.TabPageAssemblyDetails.Controls.Add(this.AssemblyNamesComboBox);
this.TabPageAssemblyDetails.Location = new System.Drawing.Point(4, 24);
this.TabPageAssemblyDetails.Name = "TabPageAssemblyDetails";
this.TabPageAssemblyDetails.Size = new System.Drawing.Size(375, 109);
this.TabPageAssemblyDetails.TabIndex = 2;
this.TabPageAssemblyDetails.Text = "Assembly Details";
//
// AssemblyDetailsListView
//
this.AssemblyDetailsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.ColumnHeader1,
this.ColumnHeader2});
this.AssemblyDetailsListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.AssemblyDetailsListView.FullRowSelect = true;
this.AssemblyDetailsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.AssemblyDetailsListView.Location = new System.Drawing.Point(0, 23);
this.AssemblyDetailsListView.Name = "AssemblyDetailsListView";
this.AssemblyDetailsListView.Size = new System.Drawing.Size(375, 86);
this.AssemblyDetailsListView.Sorting = System.Windows.Forms.SortOrder.Ascending;
this.AssemblyDetailsListView.TabIndex = 19;
this.AssemblyDetailsListView.UseCompatibleStateImageBehavior = false;
this.AssemblyDetailsListView.View = System.Windows.Forms.View.Details;
//
// ColumnHeader1
//
this.ColumnHeader1.Text = "Assembly Key";
this.ColumnHeader1.Width = 120;
//
// ColumnHeader2
//
this.ColumnHeader2.Text = "Value";
this.ColumnHeader2.Width = 700;
//
// AssemblyNamesComboBox
//
this.AssemblyNamesComboBox.Dock = System.Windows.Forms.DockStyle.Top;
this.AssemblyNamesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.AssemblyNamesComboBox.Location = new System.Drawing.Point(0, 0);
this.AssemblyNamesComboBox.Name = "AssemblyNamesComboBox";
this.AssemblyNamesComboBox.Size = new System.Drawing.Size(375, 23);
this.AssemblyNamesComboBox.Sorted = true;
this.AssemblyNamesComboBox.TabIndex = 18;
this.AssemblyNamesComboBox.SelectedIndexChanged += new System.EventHandler(this.AssemblyNamesComboBox_SelectedIndexChanged);
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.AutoSize = true;
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 8);
this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.AppCopyrightLabel, 0, 4);
this.tableLayoutPanel1.Controls.Add(this.AppDateLabel, 0, 3);
this.tableLayoutPanel1.Controls.Add(this.GroupBox1, 0, 1);
this.tableLayoutPanel1.Controls.Add(this.TabPanelDetails, 0, 7);
this.tableLayoutPanel1.Controls.Add(this.MoreRichTextBox, 0, 6);
this.tableLayoutPanel1.Controls.Add(this.AppVersionLabel, 0, 2);
this.tableLayoutPanel1.Location = new System.Drawing.Point(9, 7);
this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(2);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 9;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(389, 439);
this.tableLayoutPanel1.TabIndex = 28;
//
// tableLayoutPanel4
//
this.tableLayoutPanel4.AutoSize = true;
this.tableLayoutPanel4.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel4.ColumnCount = 3;
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel4.Controls.Add(this.buttonSystemInfo, 0, 0);
this.tableLayoutPanel4.Controls.Add(this.buttonDetails, 1, 0);
this.tableLayoutPanel4.Controls.Add(this.buttonOk, 2, 0);
this.tableLayoutPanel4.Location = new System.Drawing.Point(2, 406);
this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(2);
this.tableLayoutPanel4.Name = "tableLayoutPanel4";
this.tableLayoutPanel4.RowCount = 1;
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel4.Size = new System.Drawing.Size(249, 31);
this.tableLayoutPanel4.TabIndex = 29;
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.AutoSize = true;
this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel2.ColumnCount = 2;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 313F));
this.tableLayoutPanel2.Controls.Add(this.ImagePictureBox, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 1, 0);
this.tableLayoutPanel2.Location = new System.Drawing.Point(2, 2);
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(2);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 1;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.Size = new System.Drawing.Size(355, 46);
this.tableLayoutPanel2.TabIndex = 29;
//
// tableLayoutPanel3
//
this.tableLayoutPanel3.AutoSize = true;
this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.tableLayoutPanel3.ColumnCount = 1;
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel3.Controls.Add(this.AppTitleLabel, 0, 0);
this.tableLayoutPanel3.Controls.Add(this.AppDescriptionLabel, 0, 1);
this.tableLayoutPanel3.Location = new System.Drawing.Point(44, 2);
this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(2);
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
this.tableLayoutPanel3.RowCount = 2;
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel3.Size = new System.Drawing.Size(92, 42);
this.tableLayoutPanel3.TabIndex = 25;
//
// AboutBox
//
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.CancelButton = this.buttonOk;
this.ClientSize = new System.Drawing.Size(402, 492);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AboutBox";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "About %title%";
this.Load += new System.EventHandler(this.AboutBox_Load);
this.Paint += new System.Windows.Forms.PaintEventHandler(this.AboutBox_Paint);
((System.ComponentModel.ISupportInitialize)(this.ImagePictureBox)).EndInit();
this.TabPanelDetails.ResumeLayout(false);
this.TabPageApplication.ResumeLayout(false);
this.TabPageAssemblies.ResumeLayout(false);
this.TabPageAssemblyDetails.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel4.ResumeLayout(false);
this.tableLayoutPanel4.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.tableLayoutPanel3.ResumeLayout(false);
this.tableLayoutPanel3.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button buttonDetails;
private System.Windows.Forms.PictureBox ImagePictureBox;
private System.Windows.Forms.Label AppDateLabel;
private System.Windows.Forms.Button buttonSystemInfo;
private System.Windows.Forms.Label AppCopyrightLabel;
private System.Windows.Forms.Label AppVersionLabel;
private System.Windows.Forms.Label AppDescriptionLabel;
private System.Windows.Forms.GroupBox GroupBox1;
private System.Windows.Forms.Label AppTitleLabel;
private System.Windows.Forms.Button buttonOk;
internal System.Windows.Forms.RichTextBox MoreRichTextBox;
internal System.Windows.Forms.TabControl TabPanelDetails;
internal System.Windows.Forms.TabPage TabPageApplication;
internal System.Windows.Forms.ListView AppInfoListView;
internal System.Windows.Forms.ColumnHeader colKey;
internal System.Windows.Forms.ColumnHeader colValue;
internal System.Windows.Forms.TabPage TabPageAssemblies;
internal System.Windows.Forms.ListView AssemblyInfoListView;
internal System.Windows.Forms.ColumnHeader colAssemblyName;
internal System.Windows.Forms.ColumnHeader colAssemblyVersion;
internal System.Windows.Forms.ColumnHeader colAssemblyBuilt;
internal System.Windows.Forms.ColumnHeader colAssemblyCodeBase;
internal System.Windows.Forms.TabPage TabPageAssemblyDetails;
internal System.Windows.Forms.ListView AssemblyDetailsListView;
internal System.Windows.Forms.ColumnHeader ColumnHeader1;
internal System.Windows.Forms.ColumnHeader ColumnHeader2;
internal System.Windows.Forms.ComboBox AssemblyNamesComboBox;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022-2022 Peter Kirmeier -->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="clr-namespace:SystemTrayMenu.Utilities"
xmlns:local="clr-namespace:SystemTrayMenu.UserInterface"
x:Class="SystemTrayMenu.UserInterface.AboutBox"
mc:Ignorable="d" Title="{u:Translate 'About SystemTrayMenu'}" Height="513" Width="418" ResizeMode="NoResize" SizeToContent="Height">
<DockPanel>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Top">
<Image x:Name="ImagePictureBox" Width="32" Height="32" Margin="3" />
<StackPanel VerticalAlignment="Center">
<Label x:Name="AppTitleLabel" Content="%title%" Padding="0" Margin="3"/>
<Label x:Name="AppDescriptionLabel" Content="%description%" Padding="0" Margin="3"/>
</StackPanel>
</StackPanel>
<Separator Height="6" Margin="0" DockPanel.Dock="Top"/>
<Label x:Name="AppVersionLabel" Content="Version %title%" Padding="0" Margin="3" DockPanel.Dock="Top"/>
<Label x:Name="AppDateLabel" Content="Built on %builddate%" Padding="0" Margin="3" DockPanel.Dock="Top"/>
<Label x:Name="AppCopyrightLabel" Content="Copyright © %year%, %company%" Padding="0" Margin="3" DockPanel.Dock="Top"/>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom">
<Button x:Name="buttonSystemInfo" Content="{u:Translate 'System Info'}" Margin="3" MinWidth="79" Height="25" Click="SysInfoButton_Click"/>
<Button x:Name="buttonDetails" Content="{u:Translate 'Details'}" Margin="3" MinWidth="76" Height="25" Click="DetailsButton_Click"/>
<Button x:Name="buttonOk" Content="{u:Translate 'OK'}" Margin="3" MinWidth="76" Height="25" Click="OkButton_Click"/>
</StackPanel>
<RichTextBox x:Name="MoreRichTextBox" Height="100" DockPanel.Dock="Top" ScrollViewer.CanContentScroll="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" IsDocumentEnabled="True">
<FlowDocument>
<Paragraph>
<Run Text="%product% is %copyright%, %trademark%"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
<TabControl x:Name="TabPanelDetails" Height="149" DockPanel.Dock="Top" SelectionChanged="TabPanelDetails_SelectedIndexChanged">
<TabItem x:Name="TabPageApplication" Header="Application">
<ListView x:Name="AppInfoListView" d:ItemsSource="{d:SampleData ItemCount=2}">
<ListView.View>
<GridView>
<GridViewColumn x:Name="colKey" Header="Application Key" DisplayMemberBinding="{Binding Key}"/>
<GridViewColumn x:Name="colValue" Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</TabItem>
<TabItem x:Name="TabPageAssemblies" Header="Assemblies">
<ListView x:Name="AssemblyInfoListView" d:ItemsSource="{d:SampleData ItemCount=2}" GridViewColumnHeader.Click="AssemblyInfoListView_ColumnClick" MouseDoubleClick="AssemblyInfoListView_DoubleClick">
<ListView.View>
<GridView>
<GridViewColumn x:Name="colAssemblyName" Header="Assembly" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn x:Name="colAssemblyVersion" Header="Version" DisplayMemberBinding="{Binding Version}"/>
<GridViewColumn x:Name="colAssemblyBuilt" Header="Built" DisplayMemberBinding="{Binding Built}"/>
<GridViewColumn x:Name="colAssemblyCodeBase" Header="CodeBase" DisplayMemberBinding="{Binding CodeBase}"/>
</GridView>
</ListView.View>
</ListView>
</TabItem>
<TabItem x:Name="TabPageAssemblyDetails" Header="Assembly Details">
<DockPanel>
<ComboBox x:Name="AssemblyNamesComboBox" DockPanel.Dock="Top" SelectionChanged="AssemblyNamesComboBox_SelectedIndexChanged"/>
<ListView x:Name="AssemblyDetailsListView" d:ItemsSource="{d:SampleData ItemCount=2}">
<ListView.View>
<GridView>
<GridViewColumn x:Name="colDetailsKey" Header="Assembly Key" DisplayMemberBinding="{Binding Key}"/>
<GridViewColumn x:Name="colDetailsValue" Header="Value" DisplayMemberBinding="{Binding Value}"/>
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</TabItem>
</TabControl>
</DockPanel>
</Window>

View file

@ -1,55 +1,67 @@
// <copyright file="AboutBox.cs" company="PlaceholderCompany">
// <copyright file="AboutBox.xaml.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Collections.Specialized;
using System.Drawing;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Microsoft.Win32;
using SystemTrayMenu.Utilities;
/// <summary>
/// Generic, self-contained About Box dialog.
/// Logic of About window.
/// </summary>
/// <remarks>
/// Jeff Atwood
/// http://www.codinghorror.com
/// converted to C# by Scott Ferguson
/// http://www.forestmoon.com
/// .
/// </remarks>
internal partial class AboutBox : Form
public partial class AboutBox : Window
{
private bool isPainted;
private string entryAssemblyName;
private string callingAssemblyName;
private string executingAssemblyName;
private NameValueCollection entryAssemblyAttribCollection;
private static readonly Regex RegexUrl = new(@"(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~/|/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?");
private string? entryAssemblyName;
private string? callingAssemblyName;
private string? executingAssemblyName;
private NameValueCollection entryAssemblyAttribCollection = new();
public AboutBox()
{
InitializeComponent();
buttonOk.Text = Translator.GetText("OK");
buttonDetails.Text = Translator.GetText("Details");
buttonSystemInfo.Text = Translator.GetText("System Info");
Text = Translator.GetText("About SystemTrayMenu");
}
// <summary>
// returns the entry assembly for the current application domain
// </summary>
// <remarks>
// This is usually read-only, but in some weird cases (Smart Client apps)
// you won't have an entry assembly, so you may want to set this manually.
// </remarks>
public Assembly AppEntryAssembly { get; set; }
Assembly myassembly = Assembly.GetExecutingAssembly();
string myname = myassembly.GetName().Name ?? string.Empty;
using (Stream? imgstream = myassembly.GetManifestResourceStream(myname + ".Resources.SystemTrayMenu.png"))
{
if (imgstream != null)
{
BitmapImage imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = imgstream;
imageSource.EndInit();
ImagePictureBox.Source = imageSource;
Icon = imageSource;
}
}
Loaded += AboutBox_Load;
TabPanelDetails.Visibility = Visibility.Collapsed;
buttonSystemInfo.Visibility = Visibility.Collapsed;
}
// <summary>
// single line of text to show in the application title section of the about box dialog
@ -60,8 +72,8 @@ namespace SystemTrayMenu.UserInterface
// </remarks>
public string AppTitle
{
get => AppTitleLabel.Text;
set => AppTitleLabel.Text = value;
get => (string)AppTitleLabel.Content;
set => AppTitleLabel.Content = value;
}
// <summary>
@ -73,17 +85,17 @@ namespace SystemTrayMenu.UserInterface
// </remarks>
public string AppDescription
{
get => AppDescriptionLabel.Text;
get => (string)AppDescriptionLabel.Content;
set
{
if (string.IsNullOrEmpty(value))
{
AppDescriptionLabel.Visible = false;
AppDescriptionLabel.Visibility = Visibility.Collapsed;
}
else
{
AppDescriptionLabel.Visible = true;
AppDescriptionLabel.Text = value;
AppDescriptionLabel.Visibility = Visibility.Visible;
AppDescriptionLabel.Content = value;
}
}
}
@ -97,17 +109,17 @@ namespace SystemTrayMenu.UserInterface
// </remarks>
public string AppVersion
{
get => AppVersionLabel.Text;
get => (string)AppVersionLabel.Content;
set
{
if (string.IsNullOrEmpty(value))
{
AppVersionLabel.Visible = false;
AppVersionLabel.Visibility = Visibility.Collapsed;
}
else
{
AppVersionLabel.Visible = true;
AppVersionLabel.Text = value;
AppVersionLabel.Visibility = Visibility.Visible;
AppVersionLabel.Content = value;
}
}
}
@ -122,33 +134,21 @@ namespace SystemTrayMenu.UserInterface
// </remarks>
public string AppCopyright
{
get => AppCopyrightLabel.Text;
get => (string)AppCopyrightLabel.Content;
set
{
if (string.IsNullOrEmpty(value))
{
AppCopyrightLabel.Visible = false;
AppCopyrightLabel.Visibility = Visibility.Collapsed;
}
else
{
AppCopyrightLabel.Visible = true;
AppCopyrightLabel.Text = value;
AppCopyrightLabel.Visibility = Visibility.Visible;
AppCopyrightLabel.Content = value;
}
}
}
// <summary>
// intended for the default 32x32 application icon to appear in the upper left of the about dialog
// </summary>
// <remarks>
// if you open this form using .ShowDialog(Owner), the icon can be derived from the owning form
// </remarks>
public Image AppImage
{
get => ImagePictureBox.Image;
set => ImagePictureBox.Image = value;
}
// <summary>
// multiple lines of miscellaneous text to show in rich text box
// </summary>
@ -160,29 +160,59 @@ namespace SystemTrayMenu.UserInterface
// </remarks>
public string AppMoreInfo
{
get => MoreRichTextBox.Text;
get => new TextRange(MoreRichTextBox.Document.ContentStart, MoreRichTextBox.Document.ContentEnd).Text;
set
{
if (string.IsNullOrEmpty(value))
{
MoreRichTextBox.Visible = false;
MoreRichTextBox.Visibility = Visibility.Collapsed;
}
else
{
MoreRichTextBox.Visible = true;
MoreRichTextBox.Text = value;
MoreRichTextBox.Visibility = Visibility.Visible;
MoreRichTextBox.Document.Blocks.Clear();
Paragraph para = new Paragraph();
// Parse string to detect hyperlinks and add handlers to them
// See: https://mycsharp.de/forum/threads/97560/erledigt-dynamische-hyperlinks-in-wpf-flowdocument?page=1
int lastPos = 0;
foreach (Match match in RegexUrl.Matches(value))
{
if (match.Index != lastPos)
{
para.Inlines.Add(value.Substring(lastPos, match.Index - lastPos));
}
var link = new Hyperlink(new Run(match.Value))
{
NavigateUri = new Uri(match.Value),
};
link.Click += MoreRichTextBox_LinkClicked;
para.Inlines.Add(link);
lastPos = match.Index + match.Length;
}
if (lastPos < value.Length)
{
para.Inlines.Add(value.Substring(lastPos));
}
MoreRichTextBox.Document.Blocks.Add(para);
}
}
}
// <summary>
// determines if the "Details" (advanced assembly details) button is shown
// returns the entry assembly for the current application domain
// </summary>
public bool AppDetailsButton
{
get => buttonDetails.Visible;
set => buttonDetails.Visible = value;
}
// <remarks>
// This is usually read-only, but in some weird cases (Smart Client apps)
// you won't have an entry assembly, so you may want to set this manually.
// </remarks>
private Assembly? AppEntryAssembly { get; set; }
// <summary>
// exception-safe retrieval of LastWriteTime for this assembly.
@ -213,10 +243,10 @@ namespace SystemTrayMenu.UserInterface
// <returns>DateTime this assembly was last built</returns>
private static DateTime AssemblyBuildDate(Assembly a, bool forceFileDate)
{
Version assemblyVersion = a.GetName().Version;
Version? assemblyVersion = a.GetName().Version;
DateTime dt;
if (forceFileDate)
if (forceFileDate || assemblyVersion == null)
{
dt = AssemblyLastWriteTime(a);
}
@ -262,12 +292,12 @@ namespace SystemTrayMenu.UserInterface
string name;
string value;
NameValueCollection nvc = new();
Regex r = new(@"(\.Assembly|\.)(?<Name>[^.]*)Attribute$", RegexOptions.IgnoreCase);
Regex r = new(@"(\.Assembly|\.)(?<ColumnText>[^.]*)Attribute$", RegexOptions.IgnoreCase);
foreach (object attrib in a.GetCustomAttributes(false))
{
typeName = attrib.GetType().ToString();
name = r.Match(typeName).Groups["Name"].ToString();
name = r.Match(typeName).Groups["ColumnText"].ToString();
value = string.Empty;
switch (typeName)
{
@ -379,7 +409,7 @@ namespace SystemTrayMenu.UserInterface
{
if (!a.IsDynamic)
{
version = a.GetName().Version.ToString();
version = a.GetName().Version?.ToString() ?? version;
}
}
@ -401,8 +431,11 @@ namespace SystemTrayMenu.UserInterface
string strSysInfoPath = string.Empty;
try
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey(keyName);
strSysInfoPath = (string)rk.GetValue(subKeyRef, string.Empty);
RegistryKey? rk = Registry.LocalMachine.OpenSubKey(keyName);
if (rk != null)
{
strSysInfoPath = (string)rk.GetValue(subKeyRef, string.Empty) !;
}
}
catch (Exception ex)
{
@ -415,39 +448,41 @@ namespace SystemTrayMenu.UserInterface
// <summary>
// populate a listview with the specified key and value strings
// </summary>
private static void Populate(ListView lvw, string key, string value)
private static void Populate(ListView lvw, string key, string? value)
{
if (!string.IsNullOrEmpty(value))
{
ListViewItem lvi = new()
lvw.Items.Add(new AssemblyDetailsListViewItem
{
Text = key,
};
lvi.SubItems.Add(value);
lvw.Items.Add(lvi);
Key = key,
Value = value,
});
}
}
// <summary>
// populate details for a single assembly
// </summary>
private static void PopulateAssemblyDetails(Assembly a, ListView lvw)
private static void PopulateAssemblyDetails(Assembly? a, ListView lvw)
{
lvw.Items.Clear();
Populate(lvw, "Image Runtime Version", a.ImageRuntimeVersion);
NameValueCollection nvc = AssemblyAttribs(a);
foreach (string strKey in nvc)
if (a != null)
{
Populate(lvw, strKey, nvc[strKey]);
Populate(lvw, "Image Runtime Version", a.ImageRuntimeVersion);
NameValueCollection nvc = AssemblyAttribs(a);
foreach (string strKey in nvc)
{
Populate(lvw, strKey, nvc[strKey]);
}
}
}
// <summary>
// matches assembly by Assembly.GetName.Name; returns nothing if no match
// matches assembly by Assembly.GetName.ColumnText; returns nothing if no match
// </summary>
private static Assembly MatchAssemblyByName(string assemblyName)
private static Assembly? MatchAssemblyByName(string assemblyName)
{
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
@ -460,9 +495,9 @@ namespace SystemTrayMenu.UserInterface
return null;
}
private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e)
private void TabPanelDetails_SelectedIndexChanged(object sender, SelectionChangedEventArgs e)
{
if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails)
if (TabPanelDetails.SelectedItem == TabPageAssemblyDetails)
{
AssemblyNamesComboBox.Focus();
}
@ -485,9 +520,9 @@ namespace SystemTrayMenu.UserInterface
"System Information is unavailable at this time." +
Environment.NewLine + Environment.NewLine +
"(couldn't find path for Microsoft System Information Tool in the registry.)",
Text,
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
Title,
MessageBoxButton.OK,
MessageBoxImage.Warning);
return;
}
@ -500,9 +535,9 @@ namespace SystemTrayMenu.UserInterface
private void PopulateAppInfo()
{
AppDomain d = AppDomain.CurrentDomain;
Populate(AppInfoListView, "Application Name", Assembly.GetEntryAssembly().GetName().Name);
Populate(AppInfoListView, "Application ColumnText", Assembly.GetEntryAssembly()?.GetName().Name);
Populate(AppInfoListView, "Application Base", d.SetupInformation.ApplicationBase);
Populate(AppInfoListView, "Friendly Name", d.FriendlyName);
Populate(AppInfoListView, "Friendly ColumnText", d.FriendlyName);
Populate(AppInfoListView, " ", " ");
Populate(AppInfoListView, "Entry Assembly", entryAssemblyName);
Populate(AppInfoListView, "Executing Assembly", executingAssemblyName);
@ -519,7 +554,7 @@ namespace SystemTrayMenu.UserInterface
PopulateAssemblySummary(a);
}
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(entryAssemblyName);
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.Items.IndexOf(entryAssemblyName);
}
// <summary>
@ -529,39 +564,36 @@ namespace SystemTrayMenu.UserInterface
{
NameValueCollection nvc = AssemblyAttribs(a);
string strAssemblyName = a.GetName().Name;
ListViewItem lvi = new()
{
Text = strAssemblyName,
Tag = strAssemblyName,
};
string strAssemblyName = a.GetName().Name ?? "?";
string strAssemblyNameFull = strAssemblyName;
if (strAssemblyName == callingAssemblyName)
{
lvi.Text += " (calling)";
strAssemblyNameFull += " (calling)";
}
if (strAssemblyName == executingAssemblyName)
else if (strAssemblyName == executingAssemblyName)
{
lvi.Text += " (executing)";
strAssemblyNameFull += " (executing)";
}
if (strAssemblyName == entryAssemblyName)
else if (strAssemblyName == entryAssemblyName)
{
lvi.Text += " (entry)";
strAssemblyNameFull += " (entry)";
}
lvi.SubItems.Add(nvc["version"]);
lvi.SubItems.Add(nvc["builddate"]);
lvi.SubItems.Add(nvc["codebase"]);
AssemblyInfoListView.Items.Add(lvi);
AssemblyInfoListView.Items.Add(new AssemblyInfoListViewItem
{
Name = strAssemblyNameFull,
Version = nvc["version"] ?? string.Empty,
Built = nvc["builddate"] ?? string.Empty,
CodeBase = nvc["codebase"] ?? string.Empty,
Tag = strAssemblyName,
});
AssemblyNamesComboBox.Items.Add(strAssemblyName);
}
// <summary>
// retrieves a cached value from the entry assembly attribute lookup collection
// </summary>
private string EntryAssemblyAttrib(string strName)
private string? EntryAssemblyAttrib(string strName)
{
if (entryAssemblyAttribCollection[strName] == null)
{
@ -569,7 +601,7 @@ namespace SystemTrayMenu.UserInterface
}
else
{
return entryAssemblyAttribCollection[strName].ToString(CultureInfo.InvariantCulture);
return entryAssemblyAttribCollection[strName]?.ToString(CultureInfo.InvariantCulture);
}
}
@ -579,41 +611,34 @@ namespace SystemTrayMenu.UserInterface
private void PopulateLabels()
{
// get entry assembly attribs
entryAssemblyAttribCollection = AssemblyAttribs(AppEntryAssembly);
// set icon from parent, if present
if (Owner != null)
{
Icon = Owner.Icon;
ImagePictureBox.Image = Icon.ToBitmap();
}
entryAssemblyAttribCollection = AssemblyAttribs(AppEntryAssembly!);
// replace all labels and window title
Text = ReplaceTokens(Text);
AppTitleLabel.Text = ReplaceTokens(AppTitleLabel.Text);
if (AppDescriptionLabel.Visible)
Title = ReplaceTokens(Title);
AppTitle = ReplaceTokens(AppTitle);
if (AppDescriptionLabel.Visibility == Visibility.Visible)
{
AppDescriptionLabel.Text = ReplaceTokens(AppDescriptionLabel.Text);
AppDescription = ReplaceTokens(AppDescription);
}
if (AppCopyrightLabel.Visible)
if (AppCopyrightLabel.Visibility == Visibility.Visible)
{
AppCopyrightLabel.Text = ReplaceTokens(AppCopyrightLabel.Text);
AppCopyright = ReplaceTokens(AppCopyright);
}
if (AppVersionLabel.Visible)
if (AppVersionLabel.Visibility == Visibility.Visible)
{
AppVersionLabel.Text = ReplaceTokens(AppVersionLabel.Text);
AppVersion = ReplaceTokens(AppVersion);
}
if (AppDateLabel.Visible)
if (AppDateLabel.Visibility == Visibility.Visible)
{
AppDateLabel.Text = ReplaceTokens(AppDateLabel.Text);
AppDateLabel.Content = ReplaceTokens((string)AppDateLabel.Content);
}
if (MoreRichTextBox.Visible)
if (MoreRichTextBox.Visibility == Visibility.Visible)
{
MoreRichTextBox.Text = ReplaceTokens(MoreRichTextBox.Text);
AppMoreInfo = ReplaceTokens(AppMoreInfo);
}
}
@ -622,188 +647,160 @@ namespace SystemTrayMenu.UserInterface
// </summary>
private string ReplaceTokens(string s)
{
s = s.Replace("%title%", EntryAssemblyAttrib("title"), StringComparison.InvariantCulture);
s = s.Replace("%copyright%", EntryAssemblyAttrib("copyright"), StringComparison.InvariantCulture);
s = s.Replace("%description%", EntryAssemblyAttrib("description"), StringComparison.InvariantCulture);
s = s.Replace("%company%", EntryAssemblyAttrib("company"), StringComparison.InvariantCulture);
s = s.Replace("%product%", EntryAssemblyAttrib("product"), StringComparison.InvariantCulture);
s = s.Replace("%trademark%", EntryAssemblyAttrib("trademark"), StringComparison.InvariantCulture);
s = s.Replace("%year%", DateTime.Now.Year.ToString(CultureInfo.InvariantCulture), StringComparison.InvariantCulture);
s = s.Replace("%version%", EntryAssemblyAttrib("version"), StringComparison.InvariantCulture);
s = s.Replace("%builddate%", EntryAssemblyAttrib("builddate"), StringComparison.InvariantCulture);
return s;
return s.Replace("%title%", EntryAssemblyAttrib("title"), StringComparison.InvariantCulture)
.Replace("%copyright%", EntryAssemblyAttrib("copyright"), StringComparison.InvariantCulture)
.Replace("%description%", EntryAssemblyAttrib("description"), StringComparison.InvariantCulture)
.Replace("%company%", EntryAssemblyAttrib("company"), StringComparison.InvariantCulture)
.Replace("%product%", EntryAssemblyAttrib("product"), StringComparison.InvariantCulture)
.Replace("%trademark%", EntryAssemblyAttrib("trademark"), StringComparison.InvariantCulture)
.Replace("%year%", DateTime.Now.Year.ToString(CultureInfo.InvariantCulture), StringComparison.InvariantCulture)
.Replace("%version%", EntryAssemblyAttrib("version"), StringComparison.InvariantCulture)
.Replace("%builddate%", EntryAssemblyAttrib("builddate"), StringComparison.InvariantCulture);
}
// <summary>
// things to do when form is loaded
// </summary>
private void AboutBox_Load(object sender, EventArgs e)
private void AboutBox_Load(object sender, RoutedEventArgs e)
{
// if the user didn't provide an assembly, try to guess which one is the entry assembly
if (AppEntryAssembly == null)
{
AppEntryAssembly = Assembly.GetEntryAssembly();
}
if (AppEntryAssembly == null)
{
AppEntryAssembly = Assembly.GetExecutingAssembly();
}
AppEntryAssembly ??= Assembly.GetEntryAssembly() !;
AppEntryAssembly ??= Assembly.GetExecutingAssembly();
executingAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
callingAssemblyName = Assembly.GetCallingAssembly().GetName().Name;
// for web hosted apps, GetEntryAssembly = nothing
entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
entryAssemblyName = Assembly.GetEntryAssembly()?.GetName().Name;
TabPanelDetails.Visible = false;
if (!MoreRichTextBox.Visible)
TabPanelDetails.Visibility = Visibility.Collapsed;
if (MoreRichTextBox.Visibility != Visibility.Visible)
{
Height -= MoreRichTextBox.Height;
}
}
// <summary>
// things to do when form is FIRST painted
// </summary>
private void AboutBox_Paint(object sender, PaintEventArgs e)
{
if (!isPainted)
{
isPainted = true;
Application.DoEvents();
Cursor.Current = Cursors.WaitCursor;
PopulateLabels();
Cursor.Current = Cursors.Default;
}
Dispatcher.Invoke(
DispatcherPriority.Loaded,
new Action(delegate
{
Cursor = Cursors.Wait;
PopulateLabels();
Cursor = null;
}));
}
// <summary>
// expand about dialog to show additional advanced details
// </summary>
private void DetailsButton_Click(object sender, EventArgs e)
private void DetailsButton_Click(object sender, RoutedEventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
buttonDetails.Visible = false;
SuspendLayout();
MaximizeBox = true;
FormBorderStyle = FormBorderStyle.Sizable;
TabPanelDetails.Dock = DockStyle.Fill;
tableLayoutPanel1.Dock = DockStyle.Fill;
AutoSize = false;
SizeGripStyle = SizeGripStyle.Show;
Size = new Size(580, Size.Height);
MoreRichTextBox.Visible = false;
TabPanelDetails.Visible = true;
buttonSystemInfo.Visible = true;
Cursor = Cursors.Wait;
MoreRichTextBox.Visibility = Visibility.Collapsed;
TabPanelDetails.Visibility = Visibility.Visible;
buttonSystemInfo.Visibility = Visibility.Visible;
buttonDetails.Visibility = Visibility.Collapsed;
UpdateLayout(); // Force AutoSize to update the height before switching to manual mode
SizeToContent = SizeToContent.Manual;
ResizeMode = ResizeMode.CanResizeWithGrip;
TabPanelDetails.Height = double.NaN;
if (Width < 580)
{
Width = 580;
}
PopulateAssemblies();
PopulateAppInfo();
CenterToParent();
ResumeLayout();
Cursor.Current = Cursors.Default;
Cursor = null;
}
// <summary>
// for detailed system info, launch the external Microsoft system info app
// </summary>
private void SysInfoButton_Click(object sender, EventArgs e)
private void SysInfoButton_Click(object sender, RoutedEventArgs e)
{
ShowSysInfo();
}
/// <summary>
/// Closes the window.
/// </summary>
private void OkButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
// <summary>
// if an assembly is double-clicked, go to the detail page for that assembly
// </summary>
private void AssemblyInfoListView_DoubleClick(object sender, EventArgs e)
private void AssemblyInfoListView_DoubleClick(object sender, MouseButtonEventArgs e)
{
string strAssemblyName;
if (AssemblyInfoListView.SelectedItems.Count > 0)
{
strAssemblyName = Convert.ToString(AssemblyInfoListView.SelectedItems[0].Tag, CultureInfo.InvariantCulture);
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(strAssemblyName);
TabPanelDetails.SelectedTab = TabPageAssemblyDetails;
string? strAssemblyName = Convert.ToString(((AssemblyInfoListViewItem?)AssemblyInfoListView.SelectedItems[0])?.Tag, CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(strAssemblyName))
{
AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.Items.IndexOf(strAssemblyName);
TabPanelDetails.SelectedItem = TabPageAssemblyDetails;
}
}
}
// <summary>
// if a new assembly is selected from the combo box, show details for that assembly
// </summary>
private void AssemblyNamesComboBox_SelectedIndexChanged(object sender, EventArgs e)
private void AssemblyNamesComboBox_SelectedIndexChanged(object sender, SelectionChangedEventArgs e)
{
string strAssemblyName = Convert.ToString(AssemblyNamesComboBox.SelectedItem, CultureInfo.InvariantCulture);
PopulateAssemblyDetails(MatchAssemblyByName(strAssemblyName), AssemblyDetailsListView);
string? strAssemblyName = Convert.ToString(AssemblyNamesComboBox.SelectedItem, CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(strAssemblyName))
{
PopulateAssemblyDetails(MatchAssemblyByName(strAssemblyName), AssemblyDetailsListView);
}
}
// <summary>
// sort the assembly list by column
// </summary>
private void AssemblyInfoListView_ColumnClick(object sender, ColumnClickEventArgs e)
private void AssemblyInfoListView_ColumnClick(object sender, RoutedEventArgs e)
{
int intTargetCol = e.Column + 1;
if (AssemblyInfoListView.Tag != null)
{
if (Math.Abs(Convert.ToInt32(AssemblyInfoListView.Tag, CultureInfo.InvariantCulture)) == intTargetCol)
{
intTargetCol = -Convert.ToInt32(AssemblyInfoListView.Tag, CultureInfo.InvariantCulture);
}
}
AssemblyInfoListView.Tag = intTargetCol;
AssemblyInfoListView.ListViewItemSorter = new ListViewItemComparer(intTargetCol, true);
AssemblyInfoListView.Items.SortDescriptions.Clear();
AssemblyInfoListView.Items.SortDescriptions.Add(new SortDescription(
((GridViewColumnHeader)e.OriginalSource).Column.Header.ToString(),
ListSortDirection.Ascending));
AssemblyInfoListView.Items.Refresh();
}
// <summary>
// launch any http:// or mailto: links clicked in the body of the rich text box
// </summary>
private void MoreRichTextBox_LinkClicked(object sender, LinkClickedEventArgs e)
private void MoreRichTextBox_LinkClicked(object sender, RoutedEventArgs e)
{
Log.ProcessStart(e.LinkText);
Log.ProcessStart(((Hyperlink)sender).NavigateUri.ToString());
}
// <summary>
// things to do when the selected tab is changed
// </summary>
private class ListViewItemComparer : System.Collections.IComparer
/// <summary>
/// Type for ListView items.
/// </summary>
private class AssemblyDetailsListViewItem
{
private readonly int intCol;
private readonly bool isAscending = true;
public string Key { get; set; } = string.Empty;
public ListViewItemComparer()
{
intCol = 0;
isAscending = true;
}
public string Value { get; set; } = string.Empty;
}
public ListViewItemComparer(int column, bool ascending)
{
if (column < 0)
{
isAscending = false;
}
else
{
isAscending = ascending;
}
/// <summary>
/// Type for ListView items.
/// </summary>
private class AssemblyInfoListViewItem
{
public string Name { get; set; } = string.Empty;
intCol = Math.Abs(column) - 1;
}
public string Version { get; set; } = string.Empty;
public int Compare(object x, object y)
{
int intResult = string.Compare(
((ListViewItem)x).SubItems[intCol].Text,
((ListViewItem)y).SubItems[intCol].Text,
StringComparison.Ordinal);
if (isAscending)
{
return intResult;
}
else
{
return -intResult;
}
}
public string Built { get; set; } = string.Empty;
public string CodeBase { get; set; } = string.Empty;
public string Tag { get; set; } = string.Empty;
}
}
}
}

View file

@ -1,113 +1,115 @@
// <copyright file="AppContextMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using SystemTrayMenu.Helper.Updater;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
internal class AppContextMenu
{
public event EventHandlerEmpty ClickedOpenLog;
public ContextMenuStrip Create()
{
ContextMenuStrip menu = new()
{
BackColor = SystemColors.Control,
};
AddItem(menu, "Settings", () => 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);
AboutBox aboutBox = new()
{
AppTitle = versionInfo.ProductName,
AppDescription = versionInfo.FileDescription,
AppVersion = $"Version {versionInfo.FileVersion}",
AppCopyright = versionInfo.LegalCopyright,
AppMoreInfo = versionInfo.LegalCopyright,
};
aboutBox.AppMoreInfo += Environment.NewLine;
aboutBox.AppMoreInfo += "Markus Hofknecht (mailto:Markus@Hofknecht.eu)" + Environment.NewLine;
// Thanks for letting me being part of this project and that I am allowed to be listed here :-)
aboutBox.AppMoreInfo += "Peter Kirmeier (mai" + "lto:top" + "ete" + "rk@f" + "reen" + "et." + "de)" + Environment.NewLine;
aboutBox.AppMoreInfo += "http://www.hofknecht.eu/systemtraymenu/" + Environment.NewLine;
aboutBox.AppMoreInfo += "https://github.com/Hofknecht/SystemTrayMenu" + Environment.NewLine;
aboutBox.AppMoreInfo += Environment.NewLine;
aboutBox.AppMoreInfo += "GNU GENERAL PUBLIC LICENSE" + Environment.NewLine;
aboutBox.AppMoreInfo += "(Version 3, 29 June 2007)" + Environment.NewLine;
aboutBox.AppMoreInfo += "Thanks for ideas, reporting issues and contributing!" + Environment.NewLine;
aboutBox.AppMoreInfo += "#462 verdammt89x, #123 Mordecai00, #125 Holgermh, #135 #153 #154 #164 jakkaas, #145 Pascal Aloy, #153 #158 #160 blackcrack,";
aboutBox.AppMoreInfo += "#162 HansieNL, #163 igorruckert, #171 kehoen, #186 Dtrieb, #188 #189 #191 #195 iJahangard, #195 #197 #225 #238 the-phuctran, ";
aboutBox.AppMoreInfo += "#205 kristofzerbe, #209 jonaskohl, #211 blacksparrow15, #220 #403 Yavuz E., #229 #230 #239 Peter O., #231 Ryonez, ";
aboutBox.AppMoreInfo += "#235 #242 243 #247, #271 Tom, #237 Torsten S., #240 video Patrick, #244 Gunter D., #246 #329 MACE4GITHUB, #259 #310 vanjac, ";
aboutBox.AppMoreInfo += "#262 terencemcdonnell, #269 petersnows25, #272 Peter M., #273 #274 ParasiteDelta, #275 #276 #278 donaldaken, ";
aboutBox.AppMoreInfo += "#277 Jan S., #282 akuznets, #283 #284 #289 RuSieg, #285 #286 dao-net, #288 William P., #294 #295 #296 Stefan Mahrer, ";
aboutBox.AppMoreInfo += "#225 #297 #299 #317 #321 #324 #330 #386 #390 #401 #402 #407 #409 #414 #416 #418 #428 #430 #443 chip33, ";
aboutBox.AppMoreInfo += "#298 phanirithvij, #306 wini2, #370 dna5589, #372 not-nef, #376 Michelle H., ";
aboutBox.AppMoreInfo += "#377 SoenkeHob, #380 #394 TransLucida, #384 #434 #435 boydfields, #386 visusys, #387 #411 #444 yrctw" + Environment.NewLine;
aboutBox.AppMoreInfo += "#446 timinformatica, #450 ppt-oldoerp, #453 fubaWoW, #454 WouterVanGoey" + Environment.NewLine;
aboutBox.AppMoreInfo += @"
Sponsors - Thank you!
------------------
* Stefan Mahrer
* boydfields
* RuSieg
* Ralf K.
* donaldaken
* Marc Speer
* Peter G.
* Traditional_Tap3954
* Maximilian H.
";
aboutBox.AppDetailsButton = true;
aboutBox.ShowDialog();
}
}
// <copyright file="AppContextMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Helper
{
using System;
using System.Diagnostics;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using SystemTrayMenu.Helper.Updater;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using SystemColors = System.Windows.SystemColors;
internal class AppContextMenu
{
public event Action ClickedOpenLog;
public ContextMenu Create()
{
ContextMenu menu = new()
{
Background = SystemColors.ControlBrush,
};
AddItem(menu, "Settings", () => SettingsWindow.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);
#if TODO // GITHUBUPDATE
AddItem(menu, "Check for updates", () => GitHubUpdate.ActivateNewVersionFormOrCheckForUpdates(showWhenUpToDate: true));
#endif
AddSeperator(menu);
AddItem(menu, "Restart", AppRestart.ByAppContextMenu);
AddItem(menu, "Exit app", () => Application.Current.Shutdown());
return menu;
}
private static void AddSeperator(ContextMenu menu)
{
menu.Items.Add(new Separator());
}
private static void AddItem(
ContextMenu menu,
string text,
Action actionClick)
{
menu.Items.Add(new MenuItem()
{
Header = text,
Command = new ActionCommand((_) => actionClick()),
});
}
private static void About()
{
FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(
Assembly.GetEntryAssembly().Location);
string moreInfo = versionInfo.LegalCopyright + Environment.NewLine;
moreInfo += "Markus Hofknecht (mailto:Markus@Hofknecht.eu)" + Environment.NewLine;
// Thanks for letting me being part of this project and that I am allowed to be listed here :-)
moreInfo += "Peter Kirmeier (https://github.com/topeterk/)" + Environment.NewLine;
moreInfo += "http://www.hofknecht.eu/systemtraymenu/" + Environment.NewLine;
moreInfo += "https://github.com/Hofknecht/SystemTrayMenu" + Environment.NewLine;
moreInfo += Environment.NewLine;
moreInfo += "GNU GENERAL PUBLIC LICENSE" + Environment.NewLine;
moreInfo += "(Version 3, 29 June 2007)" + Environment.NewLine;
moreInfo += "Thanks for ideas, reporting issues and contributing!" + Environment.NewLine;
moreInfo += "#462 verdammt89x, #123 Mordecai00, #125 Holgermh, #135 #153 #154 #164 jakkaas, #145 Pascal Aloy, #153 #158 #160 blackcrack,";
moreInfo += "#162 HansieNL, #163 igorruckert, #171 kehoen, #186 Dtrieb, #188 #189 #191 #195 iJahangard, #195 #197 #225 #238 the-phuctran, ";
moreInfo += "#205 kristofzerbe, #209 jonaskohl, #211 blacksparrow15, #220 #403 Yavuz E., #229 #230 #239 Peter O., #231 Ryonez, ";
moreInfo += "#235 #242 243 #247, #271 Tom, #237 Torsten S., #240 video Patrick, #244 Gunter D., #246 #329 MACE4GITHUB, #259 #310 vanjac, ";
moreInfo += "#262 terencemcdonnell, #269 petersnows25, #272 Peter M., #273 #274 ParasiteDelta, #275 #276 #278 donaldaken, ";
moreInfo += "#277 Jan S., #282 akuznets, #283 #284 #289 RuSieg, #285 #286 dao-net, #288 William P., #294 #295 #296 Stefan Mahrer, ";
moreInfo += "#225 #297 #299 #317 #321 #324 #330 #386 #390 #401 #402 #407 #409 #414 #416 #418 #428 #430 #443 chip33, ";
moreInfo += "#298 phanirithvij, #306 wini2, #370 dna5589, #372 not-nef, #376 Michelle H., ";
moreInfo += "#377 SoenkeHob, #380 #394 TransLucida, #384 #434 #435 boydfields, #386 visusys, #387 #411 #444 yrctw" + Environment.NewLine;
moreInfo += "#446 timinformatica, #450 ppt-oldoerp, #453 fubaWoW, #454 WouterVanGoey" + Environment.NewLine;
moreInfo += @"
Sponsors - Thank you!
------------------
* Stefan Mahrer
* boydfields
* RuSieg
* Ralf K.
* donaldaken
* Marc Speer
* Peter G.
* Traditional_Tap3954
* Maximilian H.
";
AboutBox aboutBox = new()
{
AppTitle = versionInfo.ProductName,
AppDescription = versionInfo.FileDescription,
AppVersion = $"Version {versionInfo.FileVersion}",
AppCopyright = versionInfo.LegalCopyright,
AppMoreInfo = moreInfo,
};
aboutBox.ShowDialog();
}
}
}

View file

@ -1,72 +1,57 @@
// <copyright file="AppNotifyIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Windows.Forms;
using SystemTrayMenu.Helper;
using SystemTrayMenu.Utilities;
internal class AppNotifyIcon : IDisposable
{
private readonly NotifyIcon notifyIcon = new();
public AppNotifyIcon()
{
notifyIcon.Text = "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)
{
VerifyClick(e);
}
notifyIcon.MouseDoubleClick += NotifyIcon_MouseDoubleClick;
void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
VerifyClick(e);
}
}
public event EventHandlerEmpty Click;
public event EventHandlerEmpty 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();
}
}
}
// <copyright file="AppNotifyIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Windows;
using System.Windows.Input;
using Hardcodet.Wpf.TaskbarNotification;
using SystemTrayMenu.Helper;
using SystemTrayMenu.Utilities;
internal class AppNotifyIcon : IDisposable
{
private readonly TaskbarIcon notifyIcon = new ();
public AppNotifyIcon()
{
notifyIcon.ToolTipText = "SystemTrayMenu";
notifyIcon.Icon = Config.GetAppIcon();
notifyIcon.Visibility = Visibility.Visible;
AppContextMenu contextMenus = new();
contextMenus.ClickedOpenLog += ClickedOpenLog;
void ClickedOpenLog()
{
OpenLog?.Invoke();
}
notifyIcon.ContextMenu = contextMenus.Create();
notifyIcon.LeftClickCommand = new ActionCommand((_) => Click?.Invoke());
notifyIcon.DoubleClickCommand = new ActionCommand((_) => Click?.Invoke());
}
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();
}
}
}

View file

@ -203,7 +203,12 @@ namespace SystemTrayMenu.UserInterface
}
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);
}

View file

@ -1,164 +1,174 @@
// <copyright file="FolderDialog.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using SystemTrayMenu.Utilities;
public class FolderDialog : IFolderDialog, IDisposable
{
private bool isDisposed;
/// <summary>
/// Gets or sets /sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets or sets /sets directory in which dialog will be open
/// if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets or sets selected folder.
/// </summary>
public string Folder { get; set; }
public DialogResult ShowDialog()
{
return ShowDialog(owner: new WindowWrapper(IntPtr.Zero));
}
public DialogResult ShowDialog(IWin32Window owner)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
else
{
return ShowLegacyDialog(owner);
}
}
public DialogResult ShowVistaDialog(IWin32Window owner)
{
NativeMethods.IFileDialog frm = (NativeMethods.IFileDialog)new NativeMethods.FileOpenDialogRCW();
frm.GetOptions(out uint options);
options |= NativeMethods.FOS_PICKFOLDERS |
NativeMethods.FOS_FORCEFILESYSTEM |
NativeMethods.FOS_NOVALIDATE |
NativeMethods.FOS_NOTESTFILECREATE |
NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (InitialFolder != null)
{
Guid riid = new("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
InitialFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (DefaultFolder != null)
{
Guid riid = new("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
DefaultFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (owner != null && frm.Show(owner.Handle) == NativeMethods.S_OK)
{
try
{
if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK)
{
if (shellItem.GetDisplayName(
NativeMethods.SIGDN_FILESYSPATH,
out IntPtr pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try
{
Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
{
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
catch (Exception ex)
{
Log.Warn("Folder Dialog failed", ex);
}
}
return DialogResult.Cancel;
}
public DialogResult ShowLegacyDialog(IWin32Window owner)
{
using SaveFileDialog frm = new()
{
CheckFileExists = false,
CheckPathExists = true,
CreatePrompt = false,
Filter = "|" + Guid.Empty.ToString(),
FileName = "any",
};
if (InitialFolder != null)
{
frm.InitialDirectory = InitialFolder;
}
frm.OverwritePrompt = false;
frm.Title = Translator.GetText("Select directory");
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK)
{
Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
}
else
{
return DialogResult.Cancel;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
}
isDisposed = true;
}
}
}
// <copyright file="FolderDialog.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using SystemTrayMenu.Utilities;
using static SystemTrayMenu.Utilities.FormsExtensions;
public class FolderDialog : IFolderDialog, IDisposable
{
private bool isDisposed;
~FolderDialog() // the finalizer
{
Dispose(false);
}
/// <summary>
/// Gets or sets /sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets or sets /sets directory in which dialog will be open
/// if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets or sets selected folder.
/// </summary>
public string Folder { get; set; }
public DialogResult ShowDialog()
{
return ShowDialog(owner: new WindowWrapper(IntPtr.Zero));
}
public DialogResult ShowDialog(IWin32Window owner)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
else
{
return ShowLegacyDialog(owner);
}
}
public DialogResult ShowVistaDialog(IWin32Window owner)
{
NativeMethods.IFileDialog frm = (NativeMethods.IFileDialog)new NativeMethods.FileOpenDialogRCW();
frm.GetOptions(out uint options);
options |= NativeMethods.FOS_PICKFOLDERS |
NativeMethods.FOS_FORCEFILESYSTEM |
NativeMethods.FOS_NOVALIDATE |
NativeMethods.FOS_NOTESTFILECREATE |
NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (InitialFolder != null)
{
Guid riid = new("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
InitialFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (DefaultFolder != null)
{
Guid riid = new("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem
if (NativeMethods.SHCreateItemFromParsingName(
DefaultFolder,
IntPtr.Zero,
ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (owner != null && frm.Show(owner.Handle) == NativeMethods.S_OK)
{
try
{
if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK)
{
if (shellItem.GetDisplayName(
NativeMethods.SIGDN_FILESYSPATH,
out IntPtr pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try
{
Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
{
Marshal.FreeCoTaskMem(pszString);
}
}
}
}
}
catch (Exception ex)
{
Log.Warn("Folder Dialog failed", ex);
}
}
return DialogResult.Cancel;
}
public DialogResult ShowLegacyDialog(IWin32Window owner)
{
#if TODO
using SaveFileDialog frm = new()
{
CheckFileExists = false,
CheckPathExists = true,
CreatePrompt = false,
Filter = "|" + Guid.Empty.ToString(),
FileName = "any",
};
if (InitialFolder != null)
{
frm.InitialDirectory = InitialFolder;
}
frm.OverwritePrompt = false;
frm.Title = Translator.GetText("Select directory");
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK)
{
Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
}
else
{
return DialogResult.Cancel;
}
#else
return DialogResult.OK;
#endif
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!isDisposed)
{
}
isDisposed = true;
}
}
}

View file

@ -1,27 +1,26 @@
// <copyright file="IFolderDialog.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
using System.Windows.Forms;
public interface IFolderDialog
{
string InitialFolder { get; set; }
string DefaultFolder { get; set; }
string Folder { get; set; }
DialogResult ShowDialog();
DialogResult ShowDialog(IWin32Window owner);
DialogResult ShowVistaDialog(IWin32Window owner);
DialogResult ShowLegacyDialog(IWin32Window owner);
void Dispose();
}
}
// <copyright file="IFolderDialog.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
using System.Windows.Interop;
using static SystemTrayMenu.Utilities.FormsExtensions;
public interface IFolderDialog
{
string InitialFolder { get; set; }
string DefaultFolder { get; set; }
string Folder { get; set; }
DialogResult ShowDialog();
DialogResult ShowDialog(IWin32Window owner);
DialogResult ShowVistaDialog(IWin32Window owner);
DialogResult ShowLegacyDialog(IWin32Window owner);
}
}

View file

@ -4,9 +4,10 @@
namespace SystemTrayMenu.UserInterface.FolderBrowseDialog
{
using System;
public class WindowWrapper : System.Windows.Forms.IWin32Window
using System;
using System.Windows.Interop;
public class WindowWrapper : IWin32Window
{
/// <summary>
/// Initializes a new instance of the <see cref="WindowWrapper"/> class.

View file

@ -31,18 +31,18 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
private readonly IList<int> needNonShiftModifier = new List<int>();
private readonly IList<int> needNonAltGrModifier = new List<int>();
private readonly ContextMenuStrip dummy = new();
private readonly ContextMenu dummy = new();
// These variables store the current hotkey and modifier(s)
private Keys hotkey = Keys.None;
private Keys modifiers = Keys.None;
private Key hotkey = Key.None;
private Key modifiers = Key.None;
/// <summary>
/// Initializes a new instance of the <see cref="HotkeyControl"/> class.
/// </summary>
public HotkeyControl()
{
ContextMenuStrip = dummy; // Disable right-clicking
ContextMenu = dummy; // Disable right-clicking
Text = string.Empty;
// Handle events that occurs when keys are pressed
@ -77,10 +77,10 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
/// <summary>
/// Gets or sets used to make sure that there is no right-click menu available.
/// </summary>
public override ContextMenuStrip ContextMenuStrip
public override ContextMenu ContextMenu
{
get => dummy;
set => base.ContextMenuStrip = dummy;
set => base.ContextMenu = dummy;
}
/// <summary>
@ -93,9 +93,9 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
}
/// <summary>
/// Gets or sets used to get/set the hotkey (e.g. Keys.A).
/// Gets or sets used to get/set the hotkey (e.g. Key.A).
/// </summary>
public Keys Hotkey
public Key Hotkey
{
get => hotkey;
set
@ -106,9 +106,9 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
}
/// <summary>
/// Gets or sets used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control).
/// Gets or sets used to get/set the modifier keys (e.g. Key.Alt | Key.Control).
/// </summary>
public Keys HotkeyModifiers
public Key HotkeyModifiers
{
get => modifiers;
set
@ -118,30 +118,30 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
}
}
public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode)
public static string HotkeyToString(Key modifierKeyCode, Key virtualKeyCode)
{
return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode;
}
public static string HotkeyModifiersToString(Keys modifierKeyCode)
public static string HotkeyModifiersToString(Key modifierKeyCode)
{
StringBuilder hotkeyString = new();
if ((modifierKeyCode & Keys.Alt) > 0)
if ((modifierKeyCode & Key.Alt) > 0)
{
hotkeyString.Append("Alt").Append(" + ");
}
if ((modifierKeyCode & Keys.Control) > 0)
if ((modifierKeyCode & Key.Control) > 0)
{
hotkeyString.Append("Ctrl").Append(" + ");
}
if ((modifierKeyCode & Keys.Shift) > 0)
if ((modifierKeyCode & Key.Shift) > 0)
{
hotkeyString.Append("Shift").Append(" + ");
}
if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin)
if (modifierKeyCode == Key.LWin || modifierKeyCode == Key.RWin)
{
hotkeyString.Append("Win").Append(" + ");
}
@ -149,30 +149,30 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
return hotkeyString.ToString();
}
public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode)
public static string HotkeyToLocalizedString(Key modifierKeyCode, Key virtualKeyCode)
{
return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode);
}
public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode)
public static string HotkeyModifiersToLocalizedString(Key modifierKeyCode)
{
StringBuilder hotkeyString = new();
if ((modifierKeyCode & Keys.Alt) > 0)
if ((modifierKeyCode & Key.Alt) > 0)
{
hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + ");
hotkeyString.Append(GetKeyName(Key.Alt)).Append(" + ");
}
if ((modifierKeyCode & Keys.Control) > 0)
if ((modifierKeyCode & Key.Control) > 0)
{
hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + ");
hotkeyString.Append(GetKeyName(Key.Control)).Append(" + ");
}
if ((modifierKeyCode & Keys.Shift) > 0)
if ((modifierKeyCode & Key.Shift) > 0)
{
hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + ");
hotkeyString.Append(GetKeyName(Key.Shift)).Append(" + ");
}
if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin)
if (modifierKeyCode == Key.LWin || modifierKeyCode == Key.RWin)
{
hotkeyString.Append("Win").Append(" + ");
}
@ -180,39 +180,39 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
return hotkeyString.ToString();
}
public static Keys HotkeyModifiersFromString(string modifiersString)
public static Key HotkeyModifiersFromString(string modifiersString)
{
Keys modifiers = Keys.None;
Key modifiers = Key.None;
if (!string.IsNullOrEmpty(modifiersString))
{
if (modifiersString.ToUpperInvariant().Contains("ALT+", StringComparison.InvariantCulture))
{
modifiers |= Keys.Alt;
modifiers |= Key.Alt;
}
if (modifiersString.ToUpperInvariant().Contains("CTRL+", StringComparison.InvariantCulture) ||
modifiersString.ToUpperInvariant().Contains("STRG+", StringComparison.InvariantCulture))
{
modifiers |= Keys.Control;
modifiers |= Key.Control;
}
if (modifiersString.ToUpperInvariant().Contains("SHIFT+", StringComparison.InvariantCulture))
{
modifiers |= Keys.Shift;
modifiers |= Key.Shift;
}
if (modifiersString.ToUpperInvariant().Contains("WIN+", StringComparison.InvariantCulture))
{
modifiers |= Keys.LWin;
modifiers |= Key.LWin;
}
}
return modifiers;
}
public static Keys HotkeyFromString(string hotkey)
public static Key HotkeyFromString(string hotkey)
{
Keys key = Keys.None;
Key key = Key.None;
if (!string.IsNullOrEmpty(hotkey))
{
if (hotkey.LastIndexOf('+') > 0)
@ -225,7 +225,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
hotkey = hotkey.
Replace("PgDn", "PageDown", StringComparison.InvariantCulture).
Replace("PgUp", "PageUp", StringComparison.InvariantCulture);
key = (Keys)Enum.Parse(typeof(Keys), hotkey);
key = (Key)Enum.Parse(typeof(Key), hotkey);
}
catch (ArgumentException ex)
{
@ -243,31 +243,31 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
/// <param name="virtualKeyCode">The virtual key code.</param>
/// <param name="handler">A HotKeyHandler, this will be called to handle the hotkey press.</param>
/// <returns>the hotkey number, -1 if failed.</returns>
public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler)
public static int RegisterHotKey(Key modifierKeyCode, Key virtualKeyCode, HotKeyHandler handler)
{
if (virtualKeyCode == Keys.None)
if (virtualKeyCode == Key.None)
{
return 0;
}
// Convert Modifiers to fit HKM_SETHOTKEY
uint modifiers = 0;
if ((modifierKeyCode & Keys.Alt) > 0)
if ((modifierKeyCode & Key.Alt) > 0)
{
modifiers |= (uint)Modifiers.ALT;
}
if ((modifierKeyCode & Keys.Control) > 0)
if ((modifierKeyCode & Key.Control) > 0)
{
modifiers |= (uint)Modifiers.CTRL;
}
if ((modifierKeyCode & Keys.Shift) > 0)
if ((modifierKeyCode & Key.Shift) > 0)
{
modifiers |= (uint)Modifiers.SHIFT;
}
if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin)
if (modifierKeyCode == Key.LWin || modifierKeyCode == Key.RWin)
{
modifiers |= (uint)Modifiers.WIN;
}
@ -291,7 +291,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
public static void UnregisterHotkeys()
{
foreach (int hotkey in KeyHandlers.Keys)
foreach (int hotkey in KeyHandlers.Key)
{
NativeMethods.User32UnregisterHotKey(HotkeyHwnd, hotkey);
}
@ -299,27 +299,27 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
KeyHandlers.Clear();
}
public static string GetKeyName(Keys givenKey)
public static string GetKeyName(Key givenKey)
{
StringBuilder keyName = new();
const uint numpad = 55;
Keys virtualKey = givenKey;
Key virtualKey = givenKey;
string keyString = string.Empty;
// Make VC's to real keys
switch (virtualKey)
{
case Keys.Alt:
virtualKey = Keys.LMenu;
case Key.Alt:
virtualKey = Key.LMenu;
break;
case Keys.Control:
virtualKey = Keys.ControlKey;
case Key.Control:
virtualKey = Key.ControlKey;
break;
case Keys.Shift:
virtualKey = Keys.LShiftKey;
case Key.Shift:
virtualKey = Key.LShiftKey;
break;
case Keys.Multiply:
case Key.Multiply:
if (NativeMethods.User32GetKeyNameText(numpad << 16, keyName, 100) > 0)
{
keyString = keyName.ToString().Replace("*", string.Empty, StringComparison.InvariantCulture).Trim().ToLowerInvariant();
@ -332,7 +332,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
}
return keyString + " *";
case Keys.Divide:
case Key.Divide:
if (NativeMethods.User32GetKeyNameText(numpad << 16, keyName, 100) > 0)
{
keyString = keyName.ToString().Replace("*", string.Empty, StringComparison.InvariantCulture).Trim().ToLowerInvariant();
@ -352,23 +352,23 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
// because MapVirtualKey strips the extended bit for some keys
switch (virtualKey)
{
case Keys.Left:
case Keys.Up:
case Keys.Right:
case Keys.Down: // arrow keys
case Keys.Prior:
case Keys.Next: // page up and page down
case Keys.End:
case Keys.Home:
case Keys.Insert:
case Keys.Delete:
case Keys.NumLock:
case Key.Left:
case Key.Up:
case Key.Right:
case Key.Down: // arrow keys
case Key.Prior:
case Key.Next: // page up and page down
case Key.End:
case Key.Home:
case Key.Insert:
case Key.Delete:
case Key.NumLock:
scanCode |= 0x100; // set extended bit
break;
case Keys.PrintScreen: // PrintScreen
case Key.PrintScreen: // PrintScreen
scanCode = 311;
break;
case Keys.Pause: // PrintScreen
case Key.Pause: // PrintScreen
scanCode = 69;
break;
}
@ -395,13 +395,13 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
/// </summary>
public void ResetHotkey()
{
hotkey = Keys.None;
modifiers = Keys.None;
hotkey = Key.None;
modifiers = Key.None;
Redraw();
}
/// <summary>
/// Used to get/set the hotkey (e.g. Keys.A).
/// Used to get/set the hotkey (e.g. Key.A).
/// </summary>
/// <param name="hotkey">hotkey.</param>
public void SetHotkey(string hotkey)
@ -422,16 +422,16 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
/// <param name="msg">msg.</param>
/// <param name="keyData">keyData.</param>
/// <returns>bool if handled.</returns>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
protected override bool ProcessCmdKey(ref Message msg, Key keyData)
{
if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete))
if (keyData == Key.Delete || keyData == (Key.Control | Key.Delete))
{
ResetHotkey();
return true;
}
// Paste
if (keyData == (Keys.Shift | Keys.Insert))
if (keyData == (Key.Shift | Key.Insert))
{
return true; // Don't allow
}
@ -447,7 +447,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
private void Redraw(bool bCalledProgramatically = false)
{
// No hotkey set
if (hotkey == Keys.None)
if (hotkey == Key.None)
{
Text = string.Empty;
return;
@ -457,36 +457,36 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
if (bCalledProgramatically == false)
{
// No modifier or shift only, AND a hotkey that needs another modifier
if ((modifiers == Keys.Shift || modifiers == Keys.None) && needNonShiftModifier.Contains((int)hotkey))
if ((modifiers == Key.Shift || modifiers == Key.None) && needNonShiftModifier.Contains((int)hotkey))
{
if (modifiers == Keys.None)
if (modifiers == Key.None)
{
// Set Ctrl+Alt as the modifier unless Ctrl+Alt+<key> won't work...
if (needNonAltGrModifier.Contains((int)hotkey) == false)
{
modifiers = Keys.Alt | Keys.Control;
modifiers = Key.Alt | Key.Control;
}
else
{
// ... in that case, use Shift+Alt instead.
modifiers = Keys.Alt | Keys.Shift;
modifiers = Key.Alt | Key.Shift;
}
}
else
{
// User pressed Shift and an invalid key (e.g. a letter or a number),
// that needs another set of modifier keys
hotkey = Keys.None;
hotkey = Key.None;
Text = string.Empty;
return;
}
}
// Check all Ctrl+Alt keys
if ((modifiers == (Keys.Alt | Keys.Control)) && needNonAltGrModifier.Contains((int)hotkey))
if ((modifiers == (Key.Alt | Key.Control)) && needNonAltGrModifier.Contains((int)hotkey))
{
// Ctrl+Alt+4 etc won't work; reset hotkey and tell the user
hotkey = Keys.None;
hotkey = Key.None;
Text = string.Empty;
return;
}
@ -494,9 +494,9 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
// I have no idea why this is needed, but it is. Without this code, pressing only Ctrl
// will show up as "Control + ControlKey", etc.
if (hotkey == Keys.Menu /* Alt */ || hotkey == Keys.ShiftKey || hotkey == Keys.ControlKey)
if (hotkey == Key.Menu /* Alt */ || hotkey == Key.ShiftKey || hotkey == Key.ControlKey)
{
hotkey = Keys.None;
hotkey = Key.None;
}
Text = HotkeyToLocalizedString(modifiers, hotkey);
@ -509,43 +509,43 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
private void PopulateModifierLists()
{
// Shift + 0 - 9, A - Z
for (Keys k = Keys.D0; k <= Keys.Z; k++)
for (Key k = Key.D0; k <= Key.Z; k++)
{
needNonShiftModifier.Add((int)k);
}
// Shift + Numpad keys
for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++)
for (Key k = Key.NumPad0; k <= Key.NumPad9; k++)
{
needNonShiftModifier.Add((int)k);
}
// Shift + Misc (,;<./ etc)
for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++)
for (Key k = Key.Oem1; k <= Key.OemBackslash; k++)
{
needNonShiftModifier.Add((int)k);
}
// Shift + Space, PgUp, PgDn, End, Home
for (Keys k = Keys.Space; k <= Keys.Home; k++)
for (Key k = Key.Space; k <= Key.Home; k++)
{
needNonShiftModifier.Add((int)k);
}
// Misc keys that we can't loop through
needNonShiftModifier.Add((int)Keys.Insert);
needNonShiftModifier.Add((int)Keys.Help);
needNonShiftModifier.Add((int)Keys.Multiply);
needNonShiftModifier.Add((int)Keys.Add);
needNonShiftModifier.Add((int)Keys.Subtract);
needNonShiftModifier.Add((int)Keys.Divide);
needNonShiftModifier.Add((int)Keys.Decimal);
needNonShiftModifier.Add((int)Keys.Return);
needNonShiftModifier.Add((int)Keys.Escape);
needNonShiftModifier.Add((int)Keys.NumLock);
needNonShiftModifier.Add((int)Key.Insert);
needNonShiftModifier.Add((int)Key.Help);
needNonShiftModifier.Add((int)Key.Multiply);
needNonShiftModifier.Add((int)Key.Add);
needNonShiftModifier.Add((int)Key.Subtract);
needNonShiftModifier.Add((int)Key.Divide);
needNonShiftModifier.Add((int)Key.Decimal);
needNonShiftModifier.Add((int)Key.Return);
needNonShiftModifier.Add((int)Key.Escape);
needNonShiftModifier.Add((int)Key.NumLock);
// Ctrl+Alt + 0 - 9
for (Keys k = Keys.D0; k <= Keys.D9; k++)
for (Key k = Key.D0; k <= Key.D9; k++)
{
needNonAltGrModifier.Add((int)k);
}
@ -558,7 +558,7 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
private void HotkeyControl_KeyDown(object sender, KeyEventArgs e)
{
// Clear the current hotkey
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
if (e.KeyCode == Key.Back || e.KeyCode == Key.Delete)
{
ResetHotkey();
}
@ -577,14 +577,14 @@ namespace SystemTrayMenu.UserInterface.HotkeyTextboxControl
private void HotkeyControl_KeyUp(object sender, KeyEventArgs e)
{
// Somehow the PrintScreen only comes as a keyup, therefore we handle it here.
if (e.KeyCode == Keys.PrintScreen)
if (e.KeyCode == Key.PrintScreen)
{
modifiers = e.Modifiers;
hotkey = e.KeyCode;
Redraw();
}
if (hotkey == Keys.None && ModifierKeys == Keys.None)
if (hotkey == Key.None && ModifierKeys == Key.None)
{
ResetHotkey();
}

View file

@ -1,40 +0,0 @@
// <copyright file="LabelNoCopy.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace 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

@ -1,148 +0,0 @@
// <copyright file="Menu.ControlsTheDesignerRemoves.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.UserInterface
{
using System.Drawing;
using System.Windows.Forms;
using 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 = "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

@ -1,369 +0,0 @@
namespace SystemTrayMenu.UserInterface
{
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.Dispose();
fading.Dispose();
customScrollbar.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()
{
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;
}
}

View file

@ -1,63 +0,0 @@
<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>

149
UserInterface/Menu.xaml Normal file
View file

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022-2022 Peter Kirmeier -->
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:utils="clr-namespace:SystemTrayMenu.Utilities"
xmlns:local="clr-namespace:SystemTrayMenu.UserInterface"
x:Class="SystemTrayMenu.UserInterface.Menu"
mc:Ignorable="d" ResizeMode="NoResize" WindowStyle="None" Topmost="True" Background="Transparent" AllowsTransparency="True" SizeToContent="WidthAndHeight" ShowInTaskbar="False">
<Window.Effect>
<DropShadowEffect/>
</Window.Effect>
<!-- TODO WPF: Replace Fading class with built-in fading animations, like..
<Window.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Visibility}" Value="Visible">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0.0" To="1.0" Duration="0:0:5"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="1.0" To="0.0" Duration="0:0:5"
/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Style>-->
<Window.Resources>
<!-- TODO WPF Move them into separate dictionary? -->
<!-- Converted SVG images using https://github.com/BerndK/SvgToXaml/releases/tag/Ver_1.3.0 -->
<DrawingImage x:Key="ic_fluent_arrow_sync_24_regularDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M24,24z M0,0z M16.2506,5.18011C15.9994,5.50947 16.0627,5.9801 16.3921,6.23128 18.1804,7.59515 19.25,9.70821 19.25,12 19.25,15.736 16.4242,18.812 12.7933,19.2071L13.4697,18.5303C13.7626,18.2374 13.7626,17.7626 13.4697,17.4697 13.2034,17.2034 12.7867,17.1792 12.4931,17.3971L12.409,17.4697 10.409,19.4697C10.1427,19.7359,10.1185,20.1526,10.3364,20.4462L10.409,20.5303 12.409,22.5303C12.7019,22.8232 13.1768,22.8232 13.4697,22.5303 13.7359,22.2641 13.7601,21.8474 13.5423,21.5538L13.4697,21.4697 12.7194,20.7208C17.2154,20.355 20.75,16.5903 20.75,12 20.75,9.23526 19.4582,6.68321 17.3017,5.03856 16.9724,4.78738 16.5017,4.85075 16.2506,5.18011z M10.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,12 3.25,14.6445 4.43126,17.0974 6.43081,18.7491 6.75016,19.0129 7.22289,18.9679 7.48669,18.6485 7.75048,18.3292 7.70545,17.8564 7.3861,17.5926 5.72793,16.2229 4.75,14.1922 4.75,12 4.75,8.26436 7.57532,5.18861 11.2057,4.79301L10.5303,5.46967C10.2374,5.76256 10.2374,6.23744 10.5303,6.53033 10.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" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ic_fluent_folder_arrow_right_48_regularDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V48 H48 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M48,48z M0,0z M17.0607,9C17.8933,9,18.7,9.27703,19.3552,9.78393L19.5301,9.92784 22.1162,12.1907C22.3061,12.3569,22.5409,12.4609,22.7891,12.4909L22.9393,12.5 40.25,12.5C42.2543,12.5,43.8913,14.0724,43.9948,16.0508L44,16.25 44.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,15 22.8474,14.9989 20.7205,17.6147C20.0559,18.4327,19.0803,18.9305,18.035,18.9933L17.8101,19 6.5,18.999 6.5,35.25C6.5,35.8972,6.99187,36.4295,7.62219,36.4935L7.75,36.5 24.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.25 4,12.75C4,10.7457,5.57236,9.10873,7.55084,9.0052L7.75,9 17.0607,9z M17.0607,11.5L7.75,11.5C7.10279,11.5,6.57047,11.9919,6.50645,12.6222L6.5,12.75 6.5,16.499 17.8101,16.5C18.1394,16.5,18.4534,16.3701,18.6858,16.142L18.7802,16.0382 20.415,14.025 17.8838,11.8093C17.6939,11.6431,17.4591,11.5391,17.2109,11.5091L17.0607,11.5z M36,23C41.5228,23 46,27.4772 46,33 46,38.5228 41.5228,43 36,43 30.4772,43 26,38.5228 26,33 26,27.4772 30.4772,23 36,23z M35.9991,27.6342L35.8871,27.7097 35.7929,27.7929 35.7097,27.8871C35.4301,28.2467,35.4301,28.7533,35.7097,29.1129L35.7929,29.2071 38.585,32 31,32 30.8834,32.0067C30.4243,32.0601,30.06,32.4243,30.0067,32.8834L30,33 30.0067,33.1166C30.06,33.5757,30.4243,33.9399,30.8834,33.9933L31,34 38.585,34 35.7929,36.7929 35.7097,36.8871C35.4047,37.2794 35.4324,37.8466 35.7929,38.2071 36.1534,38.5676 36.7206,38.5953 37.1129,38.2903L37.2071,38.2071 41.7071,33.7071 41.7578,33.6525 41.8296,33.5585 41.8751,33.4843 41.9063,33.4232 41.9503,33.3121 41.9726,33.2335 41.9932,33.1175 42,33 41.997,32.924 41.9798,32.7992 41.9505,32.6883 41.9288,32.6287 41.8753,32.5159 41.8296,32.4415 41.7872,32.3833 41.7485,32.3369 41.7071,32.2929 37.2071,27.7929 37.1129,27.7097C36.7893,27.4581,36.3465,27.4329,35.9991,27.6342z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ic_fluent_pin_48_filledDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V48 H48 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M48,48z M0,0z 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.7678 7.76777,42 6,42 6,40.2322 15.2323,31 9.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" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ic_fluent_pin_48_regularDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V48 H48 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M48,48z M0,0z 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,31 6,40.2322 6,42 7.76777,42 17,32.7678 22.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.1824z M30.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" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ic_fluent_search_48_regularDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V48 H48 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M48,48z M0,0z M28,6C35.732,6 42,12.268 42,20 42,27.732 35.732,34 28,34 24.5841,34 21.4539,32.7766 19.0237,30.7441L8.1338,41.6339C7.6457,42.122 6.8542,42.122 6.3661,41.6339 5.8779,41.1457 5.8779,40.3543 6.3661,39.8661L17.2559,28.9763C15.2234,26.5461 14,23.4159 14,20 14,12.268 20.268,6 28,6z M39.5,20C39.5,13.6487 34.3513,8.5 28,8.5 21.6487,8.5 16.5,13.6487 16.5,20 16.5,26.3513 21.6487,31.5 28,31.5 34.3513,31.5 39.5,26.3513 39.5,20z" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<DrawingImage x:Key="ic_fluent_settings_28_regularDrawingImage">
<DrawingImage.Drawing>
<DrawingGroup ClipGeometry="M0,0 V28 H28 V0 H0 Z">
<GeometryDrawing Brush="#FF585858" Geometry="F1 M28,28z M0,0z M14,9.5C11.5147,9.5 9.5,11.5147 9.5,14 9.5,16.4853 11.5147,18.5 14,18.5 15.3488,18.5 16.559,17.9066 17.3838,16.9666 18.0787,16.1745 18.5,15.1365 18.5,14 18.5,13.5401 18.431,13.0962 18.3028,12.6783 17.7382,10.838 16.0253,9.5 14,9.5z M11,14C11,12.3431 12.3431,11 14,11 15.6569,11 17,12.3431 17,14 17,15.6569 15.6569,17 14,17 12.3431,17 11,15.6569 11,14z" />
<GeometryDrawing Brush="#FF585858" Geometry="F1 M28,28z M0,0z M21.7093,22.3947L19.9818,21.6364C19.4876,21.4197 18.9071,21.4514 18.44,21.7219 17.9729,21.9923 17.675,22.4692 17.6157,23.0065L17.408,24.8855C17.3651,25.2729 17.084,25.5917 16.7055,25.6819 14.9263,26.106 13.0725,26.106 11.2933,25.6819 10.9148,25.5917 10.6336,25.2729 10.5908,24.8855L10.3834,23.0093C10.3225,22.473 10.0112,21.9976 9.54452,21.728 9.07783,21.4585 8.51117,21.4269 8.01859,21.6424L6.29071,22.4009C5.93281,22.558 5.51493,22.4718 5.24806,22.1858 4.00474,20.8536 3.07924,19.2561 2.54122,17.5136 2.42533,17.1383 2.55922,16.7307 2.8749,16.4976L4.40219,15.3703C4.83721,15.05 5.09414,14.5415 5.09414,14.0006 5.09414,13.4597 4.83721,12.9512 4.40162,12.6305L2.87529,11.5051C2.55914,11.272 2.42513,10.8638 2.54142,10.4881 3.08038,8.74728 4.00637,7.15157 5.24971,5.82108 5.51684,5.53522 5.93492,5.44935 6.29276,5.60685L8.01296,6.36398C8.50793,6.58162 9.07696,6.54875 9.54617,6.27409 10.0133,6.00258 10.3244,5.52521 10.3844,4.98787L10.5933,3.11011C10.637,2.71797 10.9245,2.39697 11.3089,2.31131 12.19,2.11498 13.0891,2.01065 14.0131,2 14.9147,2.01041 15.8128,2.11478 16.6928,2.31143 17.077,2.39728 17.3643,2.71817 17.4079,3.11011L17.617,4.98931C17.7116,5.85214 18.4387,6.50566 19.3055,6.50657 19.5385,6.50694 19.769,6.45832 19.9843,6.36288L21.7048,5.60562C22.0626,5.44812 22.4807,5.53399 22.7478,5.81984 23.9912,7.15034 24.9172,8.74605 25.4561,10.4869 25.5723,10.8623 25.4386,11.2702 25.1228,11.5034L23.5978,12.6297C23.1628,12.9499 22.9,13.4585 22.9,13.9994 22.9,14.5402 23.1628,15.0488 23.5988,15.3697L25.1251,16.4964C25.441,16.7296 25.5748,17.1376 25.4586,17.513 24.9198,19.2536 23.9944,20.8491 22.7517,22.1799 22.4849,22.4657 22.0671,22.5518 21.7093,22.3947z M16.263,22.1965C16.4982,21.4684 16.9889,20.8288 17.6884,20.4238 18.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.5777 22.7086,16.577C21.898,15.9799 21.4,15.0276 21.4,13.9994 21.4,12.9718 21.8974,12.0195 22.7073,11.4227L22.7085,11.4217 23.8957,10.545C23.4567,9.29874,22.7881,8.1463,21.9248,7.14764L20.5922,7.73419 20.5899,7.73521C20.1844,7.91457 19.7472,8.00716 19.3039,8.00657 17.6715,8.00447 16.3046,6.77425 16.1261,5.15459L16.1259,5.15285 15.9635,3.69298C15.3202,3.57322 14.6677,3.50866 14.013,3.50011 13.3389,3.50885 12.6821,3.57361 12.0377,3.69322L11.8751,5.15446C11.7625,6.16266 11.1793,7.05902 10.3019,7.5698 9.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.0006 6.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.4291 11.174,20.9369 11.7593,21.8319 11.8738,22.84L11.8744,22.8445 12.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" />
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
<sys:Double x:Key="RowHeight">20</sys:Double>
<sys:Double x:Key="ColumnIconWidth">20</sys:Double>
<sys:Double x:Key="ColumnTextWidth">60</sys:Double>
</Window.Resources>
<Border x:Name="windowFrame" BorderBrush="#FF000000" BorderThickness="1" CornerRadius="0" Background="White" HorizontalAlignment="Center" VerticalAlignment="Center">
<DockPanel x:Name="tableLayoutPanelMenu">
<Label x:Name="labelTitle" DockPanel.Dock="Top" HorizontalContentAlignment="Center" Padding="1" Margin="6,0" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="txtTitle" TextTrimming="CharacterEllipsis" Margin="14,0"><Run Text="title"/></TextBlock>
</Label>
<DockPanel x:Name="searchPanel" DockPanel.Dock="Top" Margin="6,0">
<Image x:Name="pictureBoxSearch" Width="16" Height="16" Margin="1" DockPanel.Dock="Left" Source="{StaticResource ic_fluent_search_48_regularDrawingImage}"/>
<TextBox x:Name="textBoxSearch" BorderBrush="{x:Null}" TextInput="textBoxSearch_TextInput" Background="{x:Null}" />
</DockPanel>
<Separator x:Name="panelLine" Height="1" Margin="6,1" DockPanel.Dock="Top"/>
<DockPanel x:Name="tableLayoutPanelBottom" DockPanel.Dock="Bottom" Margin="12,4">
<Label x:Name="labelItems" Content="0 items" Padding="0" DockPanel.Dock="Left" FontWeight="Bold" VerticalAlignment="Center" Margin="0,0,10,0"/>
<Button x:Name="buttonRestart" Width="18" Height="18" Padding="0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderBrush="{x:Null}" Background="{x:Null}" Click="PictureBoxRestart_MouseClick" >
<Image x:Name="pictureBoxRestart" Source="{StaticResource ic_fluent_arrow_sync_24_regularDrawingImage}"/>
</Button>
<Button x:Name="buttonSettings" Width="18" Height="18" Padding="0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderBrush="{x:Null}" Background="{x:Null}" Click="PictureBoxSettings_MouseClick" >
<Image x:Name="pictureBoxSettings" Source="{StaticResource ic_fluent_settings_28_regularDrawingImage}"/>
</Button>
<Button x:Name="buttonMenuAlwaysOpen" Width="18" Height="18" Padding="0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderBrush="{x:Null}" Background="{x:Null}" Click="PictureBoxMenuAlwaysOpen_Click" >
<Image x:Name="pictureBoxMenuAlwaysOpen" Source="{StaticResource ic_fluent_pin_48_regularDrawingImage}"/>
</Button>
<Button x:Name="buttonOpenFolder" Width="18" Height="18" Padding="0" DockPanel.Dock="Right" HorizontalAlignment="Right" BorderBrush="{x:Null}" Background="{x:Null}" Click="PictureBoxOpenFolder_Click" >
<Image x:Name="pictureBoxOpenFolder" Source="{StaticResource ic_fluent_folder_arrow_right_48_regularDrawingImage}"/>
</Button>
</DockPanel>
<ListView x:Name="dgv" x:FieldModifier="internal" Margin="6,0" d:ItemsSource="{d:SampleData ItemCount=5}" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" BorderBrush="{x:Null}" Background="{x:Null}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="{DynamicResource ColumnIconWidth}" Source="{Binding ColumnIcon, Converter={utils:IconToImageSourceConverter}}"/>
<Label Width="{DynamicResource ColumnTextWidth}" Margin="6,0" Padding="0" VerticalContentAlignment="Center">
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding ColumnText}"/>
</Label>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="MouseEnter" Handler="ListViewItem_MouseEnter" />
<EventSetter Event="MouseLeave" Handler="ListViewItem_MouseLeave" />
<EventSetter Event="PreviewMouseDown" Handler="ListViewItem_MouseDown" />
<EventSetter Event="MouseUp" Handler="ListViewItem_MouseUp" />
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewxItem_PreviewMouseLeftButtonDown" />
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</DockPanel>
</Border>
</Window>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,75 +0,0 @@
<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="ColumnFolder.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ColumnRecursiveLevel.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="ColumnOnlyFiles.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="colorDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>42</value>
</metadata>
</root>

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022-2022 Peter Kirmeier -->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="clr-namespace:SystemTrayMenu.Utilities"
xmlns:local="clr-namespace:SystemTrayMenu.UserInterface"
x:Class="SystemTrayMenu.UserInterface.SettingsWindow"
mc:Ignorable="d" Title="{u:Translate 'Settings'}" WindowStartupLocation="CenterScreen" SizeToContent="WidthAndHeight">
<StackPanel>
<TabControl>
<TabItem Header="{u:Translate 'General'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 1" Background="Red"/>
</ScrollViewer>
</TabItem>
<TabItem Header="{u:Translate 'Size and location'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 2" Background="Red"/>
</ScrollViewer>
</TabItem>
<TabItem Header="{u:Translate 'Advanced'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 3" Background="Red"/>
</ScrollViewer>
</TabItem>
<TabItem Header="{u:Translate 'Directories'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 4" Background="Red"/>
</ScrollViewer>
</TabItem>
<TabItem Header="{u:Translate 'Expert'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 5" Background="Red"/>
</ScrollViewer>
</TabItem>
<TabItem Header="{u:Translate 'Customize'}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Label Content="fill me 6" Background="Red"/>
</ScrollViewer>
</TabItem>
</TabControl>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Right">
<Button x:Name="buttonOk" Content="{u:Translate 'OK'}" Margin="3" MinWidth="76" Height="25" Click="ButtonOk_Click"/>
<Button x:Name="buttonCancel" Content="{u:Translate 'Abort'}" Margin="3" MinWidth="76" Height="25" Click="ButtonCancel_Click"/>
</StackPanel>
</StackPanel>
</Window>

File diff suppressed because it is too large Load diff

View file

@ -1,55 +0,0 @@
namespace 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

@ -1,39 +0,0 @@
// <copyright file="TaskbarForm.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace 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,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2022-2022 Peter Kirmeier -->
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SystemTrayMenu.UserInterface"
x:Class="SystemTrayMenu.UserInterface.TaskbarLogo"
mc:Ignorable="d" WindowStyle="None" ResizeMode="NoResize" Width="38" Height="38" Topmost="True" Background="Transparent" AllowsTransparency="True">
<Image x:Name="ImagePictureBox" Width="32" Height="32" Margin="3"/>
</Window>

View file

@ -0,0 +1,90 @@
// <copyright file="TaskbarLogo.xaml.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
#nullable enable
namespace SystemTrayMenu.UserInterface
{
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using SystemTrayMenu.DllImports;
/// <summary>
/// Logic of Taskbar window.
/// </summary>
public partial class TaskbarLogo : Window
{
private DispatcherTimer? moveOutOfScreenTimer = null;
public TaskbarLogo()
{
InitializeComponent();
Assembly myassembly = Assembly.GetExecutingAssembly();
string myname = myassembly.GetName().Name ?? string.Empty;
using (Stream? imgstream = myassembly.GetManifestResourceStream(myname + ".Resources.SystemTrayMenu.png"))
{
if (imgstream != null)
{
BitmapImage imageSource = new BitmapImage();
imageSource.BeginInit();
imageSource.StreamSource = imgstream;
imageSource.EndInit();
ImagePictureBox.Source = imageSource;
}
}
Icon = Imaging.CreateBitmapSourceFromHIcon(
Config.GetAppIcon().Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
Title = myname;
Closed += (_, _) => Application.Current.Shutdown();
Deactivated += (_, _) => SetStateNormal();
Activated += (_, _) =>
{
SetStateNormal();
Activate();
UpdateLayout();
Focus();
moveOutOfScreenTimer = new DispatcherTimer(
TimeSpan.FromMilliseconds(500),
DispatcherPriority.Loaded,
(s, e) =>
{
// Do this after loading because Top may be invalid at the beginning
// and when initial rendering is out of screen it will never be actually painted.
// This makes sure logo is rendered once and then window is moved.
Top += SystemParameters.VirtualScreenHeight;
((DispatcherTimer)s!).IsEnabled = false; // only once
},
Dispatcher.CurrentDispatcher);
};
}
/// <summary>
/// This ensures that next click on taskbaritem works as activate event/click event.
/// </summary>
private void SetStateNormal()
{
if (IsActive)
{
WindowState = WindowState.Normal;
}
}
}
}

View file

@ -0,0 +1,31 @@
// <copyright file="ActionCommand.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.Utilities
{
using System;
using System.Windows.Input;
internal class ActionCommand : ICommand
{
private readonly Action<object> action;
public ActionCommand(Action<object> action)
{
this.action = action;
}
#pragma warning disable CS0067
public event EventHandler? CanExecuteChanged;
#pragma warning restore CS0067
public bool CanExecute(object? parameter) => true;
public void Execute(object? parameter) => action.Invoke(parameter!);
}
}

View file

@ -1,69 +1,70 @@
// <copyright file="AppRestart.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
internal class AppRestart
{
public static event EventHandlerEmpty BeforeRestarting;
internal static void ByThreadException()
{
Restart(GetCurrentMethod());
}
internal static void ByAppContextMenu()
{
Restart(GetCurrentMethod());
}
internal static void ByConfigChange()
{
Restart(GetCurrentMethod());
}
internal static void ByMenuButton()
{
Restart(GetCurrentMethod());
}
private static void Restart(string reason)
{
BeforeRestarting?.Invoke();
Log.Info($"Restart by '{reason}'");
Log.Close();
using (Process p = new())
{
string fileName = System.Environment.ProcessPath;
p.StartInfo = new ProcessStartInfo(fileName);
try
{
p.Start();
}
catch (Win32Exception ex)
{
Log.Warn("Restart failed", ex);
}
}
Application.Exit();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetCurrentMethod()
{
StackTrace st = new();
StackFrame sf = st.GetFrame(1);
return sf.GetMethod().Name;
}
}
}
// <copyright file="AppRestart.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;
internal class AppRestart
{
public static event Action BeforeRestarting;
internal static void ByThreadException()
{
Restart(GetCurrentMethod());
}
internal static void ByAppContextMenu()
{
Restart(GetCurrentMethod());
}
internal static void ByConfigChange()
{
Restart(GetCurrentMethod());
}
internal static void ByMenuButton()
{
Restart(GetCurrentMethod());
}
private static void Restart(string reason)
{
BeforeRestarting?.Invoke();
Log.Info($"Restart by '{reason}'");
Log.Close();
using (Process p = new())
{
string fileName = System.Environment.ProcessPath;
p.StartInfo = new ProcessStartInfo(fileName);
try
{
p.Start();
}
catch (Win32Exception ex)
{
Log.Warn("Restart failed", ex);
}
}
Application.Current.Shutdown();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetCurrentMethod()
{
StackTrace st = new();
StackFrame sf = st.GetFrame(1);
return sf.GetMethod().Name;
}
}
}

View file

@ -1,49 +0,0 @@
// <copyright file="DataGridViewExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using 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 * (Properties.Settings.Default.WidthMaxInPercent / 100f));
widthMax = Math.Min(widthMax, widthMaxInPixel);
dgv.Columns[1].Width = (int)(widthMax + 0.5);
double factorIconSizeInPercent = Properties.Settings.Default.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

@ -1,8 +0,0 @@
// <copyright file="EventHandlerEmpty.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
public delegate void EventHandlerEmpty();
}

View file

@ -1,24 +1,58 @@
// <copyright file="FormsExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace 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();
}
}
}
}
// <copyright file="FormsExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
public static class FormsExtensions
{
public enum DialogResult
{
OK,
Cancel,
Ignore,
Retry,
}
public class NativeWindow : HwndSource
{
private HwndSourceHook hook;
public NativeWindow()
: base(new())
{
hook = new HwndSourceHook(WndProc);
AddHook(hook);
}
~NativeWindow()
{
RemoveHook(hook);
}
protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
throw new NotImplementedException();
}
}
#if TODO
public static void HandleInvoke(this Control instance, Action action)
{
if (instance.InvokeRequired)
{
instance.Invoke(action);
}
else
{
action();
}
}
#endif
}
}

View file

@ -0,0 +1,47 @@
// <copyright file="IconToImageSourceConverter.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
namespace SystemTrayMenu.Utilities
{
using System;
using System.Drawing;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
[ValueConversion(typeof(Icon), typeof(ImageSource))]
public class IconToImageSourceConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
// Invalid Icon happens usually only during design time with dummy default data
Icon icon = value is Icon ? (Icon)value : SystemIcons.Error;
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
return null!;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
}

View file

@ -1,199 +1,199 @@
// <copyright file="Log.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Clearcove.Logging;
internal static class Log
{
private const string LogfileLastExtension = "_last";
private static readonly Logger LogValue = new(string.Empty);
private static readonly List<string> Warnings = new();
private static readonly List<string> Infos = new();
internal static void Initialize()
{
bool warnFailedToSaveLogFile = false;
Exception exceptionWarnFailedToSaveLogFile = new();
if (Properties.Settings.Default.SaveLogFileInApplicationDirectory)
{
try
{
string fileNameToCheckWriteAccess = "CheckWriteAccess";
File.WriteAllText(fileNameToCheckWriteAccess, fileNameToCheckWriteAccess);
File.Delete(fileNameToCheckWriteAccess);
}
catch (Exception ex)
{
Properties.Settings.Default.SaveLogFileInApplicationDirectory = false;
warnFailedToSaveLogFile = true;
exceptionWarnFailedToSaveLogFile = ex;
}
}
bool warnCanNotClearLogfile = false;
Exception exceptionWarnCanNotClearLogfile = new();
string fileNamePath = GetLogFilePath();
FileInfo fileInfo = new(fileNamePath);
string fileNamePathLast = string.Empty;
if (fileInfo.Exists && fileInfo.Length > 2000000)
{
fileNamePathLast = GetLogFilePath(LogfileLastExtension);
try
{
File.Delete(fileNamePathLast);
File.Move(fileNamePath, fileNamePathLast);
}
catch (Exception ex)
{
warnCanNotClearLogfile = true;
exceptionWarnCanNotClearLogfile = ex;
}
}
Logger.Start(fileInfo);
if (warnFailedToSaveLogFile)
{
Warn($"Failed to save log file in application folder {GetLogFilePath()}", exceptionWarnFailedToSaveLogFile);
}
if (warnCanNotClearLogfile)
{
Warn($"Can not clear logfile:'{fileNamePathLast}'", exceptionWarnCanNotClearLogfile);
}
}
internal static void Info(string message)
{
if (!Infos.Contains(message))
{
Infos.Add(message);
LogValue.Info(message);
}
}
internal static void Warn(string message, Exception ex)
{
string warning = $"{message} {ex.ToString().Replace(Environment.NewLine, " ", StringComparison.InvariantCulture)}";
if (!Warnings.Contains(warning))
{
Warnings.Add(warning);
LogValue.Warn(warning);
}
}
internal static void Error(string message, Exception ex)
{
LogValue.Error($"{message}{Environment.NewLine}" +
$"{ex}");
}
internal static string GetLogFilePath(string backup = "")
{
string logFilePath = string.Empty;
if (!Properties.Settings.Default.SaveLogFileInApplicationDirectory)
{
logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), $"SystemTrayMenu");
}
return Path.Combine(logFilePath, $"log-{Environment.MachineName}{backup}.txt");
}
internal static void OpenLogFile()
{
string lastLogfile = GetLogFilePath(LogfileLastExtension);
if (File.Exists(lastLogfile))
{
ProcessStart(lastLogfile);
}
ProcessStart(GetLogFilePath());
}
internal static void WriteApplicationRuns()
{
Assembly assembly = Assembly.GetExecutingAssembly();
LogValue.Info($"Application Start " +
assembly.ManifestModule.Name + " | " +
assembly.GetName().Version.ToString() + " | " +
$"ScalingFactor={Scaling.Factor}");
}
internal static void Close()
{
try
{
Logger.ShutDown();
}
catch (Exception ex)
{
Properties.Settings.Default.SaveLogFileInApplicationDirectory = false;
Warn($"Failed to save log file in application folder {GetLogFilePath()}", ex);
}
}
internal static void ProcessStart(
string fileName,
string arguments = "",
bool doubleQuoteArg = false,
string workingDirectory = "",
bool createNoWindow = false,
string resolvedPath = "")
{
if (doubleQuoteArg && !string.IsNullOrEmpty(arguments))
{
arguments = "\"" + arguments + "\"";
}
try
{
using Process p = new()
{
StartInfo = new ProcessStartInfo(fileName)
{
FileName = fileName,
Arguments = arguments,
WorkingDirectory = workingDirectory,
CreateNoWindow = createNoWindow,
UseShellExecute = true,
},
};
p.Start();
}
catch (Win32Exception ex)
{
Warn($"fileName:'{fileName}' arguments:'{arguments}'", ex);
if ((ex.NativeErrorCode == 2 || ex.NativeErrorCode == 1223) &&
(string.IsNullOrEmpty(resolvedPath) || !File.Exists(resolvedPath)))
{
new Thread(ShowProblemWithShortcut).Start();
static void ShowProblemWithShortcut()
{
_ = MessageBox.Show(
Translator.GetText("The item that this shortcut refers to has been changed or moved, so this shortcut will no longer work properly."),
Translator.GetText("Problem with shortcut link"),
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
}
}
catch (Exception ex)
{
Warn($"fileName:'{fileName}' arguments:'{arguments}'", ex);
}
}
}
}
// <copyright file="Log.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using Clearcove.Logging;
internal static class Log
{
private const string LogfileLastExtension = "_last";
private static readonly Logger LogValue = new(string.Empty);
private static readonly List<string> Warnings = new();
private static readonly List<string> Infos = new();
internal static void Initialize()
{
bool warnFailedToSaveLogFile = false;
Exception exceptionWarnFailedToSaveLogFile = new();
if (Properties.Settings.Default.SaveLogFileInApplicationDirectory)
{
try
{
string fileNameToCheckWriteAccess = "CheckWriteAccess";
File.WriteAllText(fileNameToCheckWriteAccess, fileNameToCheckWriteAccess);
File.Delete(fileNameToCheckWriteAccess);
}
catch (Exception ex)
{
Properties.Settings.Default.SaveLogFileInApplicationDirectory = false;
warnFailedToSaveLogFile = true;
exceptionWarnFailedToSaveLogFile = ex;
}
}
bool warnCanNotClearLogfile = false;
Exception exceptionWarnCanNotClearLogfile = new();
string fileNamePath = GetLogFilePath();
FileInfo fileInfo = new(fileNamePath);
string fileNamePathLast = string.Empty;
if (fileInfo.Exists && fileInfo.Length > 2000000)
{
fileNamePathLast = GetLogFilePath(LogfileLastExtension);
try
{
File.Delete(fileNamePathLast);
File.Move(fileNamePath, fileNamePathLast);
}
catch (Exception ex)
{
warnCanNotClearLogfile = true;
exceptionWarnCanNotClearLogfile = ex;
}
}
Logger.Start(fileInfo);
if (warnFailedToSaveLogFile)
{
Warn($"Failed to save log file in application folder {GetLogFilePath()}", exceptionWarnFailedToSaveLogFile);
}
if (warnCanNotClearLogfile)
{
Warn($"Can not clear logfile:'{fileNamePathLast}'", exceptionWarnCanNotClearLogfile);
}
}
internal static void Info(string message)
{
if (!Infos.Contains(message))
{
Infos.Add(message);
LogValue.Info(message);
}
}
internal static void Warn(string message, Exception ex)
{
string warning = $"{message} {ex.ToString().Replace(Environment.NewLine, " ", StringComparison.InvariantCulture)}";
if (!Warnings.Contains(warning))
{
Warnings.Add(warning);
LogValue.Warn(warning);
}
}
internal static void Error(string message, Exception ex)
{
LogValue.Error($"{message}{Environment.NewLine}" +
$"{ex}");
}
internal static string GetLogFilePath(string backup = "")
{
string logFilePath = string.Empty;
if (!Properties.Settings.Default.SaveLogFileInApplicationDirectory)
{
logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), $"SystemTrayMenu");
}
return Path.Combine(logFilePath, $"log-{Environment.MachineName}{backup}.txt");
}
internal static void OpenLogFile()
{
string lastLogfile = GetLogFilePath(LogfileLastExtension);
if (File.Exists(lastLogfile))
{
ProcessStart(lastLogfile);
}
ProcessStart(GetLogFilePath());
}
internal static void WriteApplicationRuns()
{
Assembly assembly = Assembly.GetExecutingAssembly();
LogValue.Info($"Application Start " +
assembly.ManifestModule.Name + " | " +
assembly.GetName().Version.ToString() + " | " +
$"ScalingFactor={Scaling.Factor}");
}
internal static void Close()
{
try
{
Logger.ShutDown();
}
catch (Exception ex)
{
Properties.Settings.Default.SaveLogFileInApplicationDirectory = false;
Warn($"Failed to save log file in application folder {GetLogFilePath()}", ex);
}
}
internal static void ProcessStart(
string fileName,
string arguments = "",
bool doubleQuoteArg = false,
string workingDirectory = "",
bool createNoWindow = false,
string resolvedPath = "")
{
if (doubleQuoteArg && !string.IsNullOrEmpty(arguments))
{
arguments = "\"" + arguments + "\"";
}
try
{
using Process p = new()
{
StartInfo = new ProcessStartInfo(fileName)
{
FileName = fileName,
Arguments = arguments,
WorkingDirectory = workingDirectory,
CreateNoWindow = createNoWindow,
UseShellExecute = true,
},
};
p.Start();
}
catch (Win32Exception ex)
{
Warn($"fileName:'{fileName}' arguments:'{arguments}'", ex);
if ((ex.NativeErrorCode == 2 || ex.NativeErrorCode == 1223) &&
(string.IsNullOrEmpty(resolvedPath) || !File.Exists(resolvedPath)))
{
new Thread(ShowProblemWithShortcut).Start();
static void ShowProblemWithShortcut()
{
_ = MessageBox.Show(
Translator.GetText("The item that this shortcut refers to has been changed or moved, so this shortcut will no longer work properly."),
Translator.GetText("Problem with shortcut link"),
MessageBoxButton.OK,
MessageBoxImage.Warning);
}
}
}
catch (Exception ex)
{
Warn($"fileName:'{fileName}' arguments:'{arguments}'", ex);
}
}
}
}

View file

@ -1,31 +1,50 @@
// <copyright file="Scaling.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Drawing;
internal static class Scaling
{
public static float Factor { get; private set; } = 1;
public static float FactorByDpi { get; private set; } = 1;
public static void Initialize()
{
Factor = Properties.Settings.Default.SizeInPercent / 100f;
}
public static int Scale(int width)
{
return (int)Math.Round(width * Factor, 0, MidpointRounding.AwayFromZero);
}
public static void CalculateFactorByDpi(Graphics graphics)
{
FactorByDpi = graphics.DpiX / 96;
}
}
}
// <copyright file="Scaling.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.Utilities
{
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Media;
internal static class Scaling
{
private static FontSizeConverter fontConverter = new FontSizeConverter();
public static float Factor { get; private set; } = 1;
public static double FactorByDpi { get; private set; } = 1;
public static void Initialize()
{
Factor = Properties.Settings.Default.SizeInPercent / 100f;
}
public static int Scale(int width)
{
return (int)Math.Round(width * Factor, 0, MidpointRounding.AwayFromZero);
}
public static double Scale(double width)
{
return Math.Round(width * Factor, 0, MidpointRounding.AwayFromZero);
}
public static double ScaleFontByPoints(float points)
{
return (double)fontConverter.ConvertFrom((points * Factor).ToString() + "pt") !;
}
public static double ScaleFontByPixels(float pixels)
{
return pixels * Factor;
}
public static void CalculateFactorByDpi(Window window)
{
FactorByDpi = VisualTreeHelper.GetDpi(window).DpiScaleX;
}
}
}

View file

@ -7,8 +7,8 @@ namespace SystemTrayMenu.Utilities
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using System.Linq;
using System.Windows.Input;
using SystemTrayMenu.UserInterface.HotkeyTextboxControl;
using WindowsInput;
@ -25,9 +25,10 @@ namespace SystemTrayMenu.Utilities
Where(s => s.Id != Environment.ProcessId))
{
if (Properties.Settings.Default.SendHotkeyInsteadKillOtherInstances)
{
Keys modifiers = HotkeyControl.HotkeyModifiersFromString(Properties.Settings.Default.HotKey);
Keys hotkey = HotkeyControl.HotkeyFromString(Properties.Settings.Default.HotKey);
{
#if TODO //HOTKEY
Key modifiers = HotkeyControl.HotkeyModifiersFromString(Properties.Settings.Default.HotKey);
Key hotkey = HotkeyControl.HotkeyFromString(Properties.Settings.Default.HotKey);
try
{
@ -62,7 +63,8 @@ namespace SystemTrayMenu.Utilities
catch (Exception ex)
{
Log.Warn($"Send hoktey {Properties.Settings.Default.HotKey} to other instance failed", ex);
}
}
#endif
}
if (!Properties.Settings.Default.SendHotkeyInsteadKillOtherInstances)

25
Utilities/Translate.cs Normal file
View file

@ -0,0 +1,25 @@
// <copyright file="Translate.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.Utilities
{
using System;
using System.Windows.Markup;
public class Translate : MarkupExtension
{
private readonly string original;
public Translate(string original)
{
this.original = original;
}
public override object ProvideValue(IServiceProvider serviceProvider) => Translator.GetText(original);
}
}

View file

@ -0,0 +1,65 @@
// <copyright file="WPFExtensions.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
//
// Copyright (c) 2022-2022 Peter Kirmeier
#nullable enable
namespace SystemTrayMenu.Utilities
{
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
internal static class WPFExtensions
{
internal static Window GetParentWindow(this ListView listView)
{
var parent = VisualTreeHelper.GetParent(listView);
while (!(parent is Window))
{
parent = VisualTreeHelper.GetParent(parent);
}
return (Window)parent;
}
internal static T? FindVisualChildOfType<T>(this DependencyObject depObj, int index = 0)
where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null)
{
if (child is T)
{
if (index-- == 0)
{
return (T)child;
}
continue;
}
T? childItem = child.FindVisualChildOfType<T>(index);
if (childItem != null)
{
return childItem;
}
}
}
return null;
}
internal static Point GetRelativeChildPositionTo(this Visual parent, Visual child)
{
var pt = child.TransformToAncestor(parent).Transform(new(0, 0));
return new (pt.X, pt.Y);
}
}
}