#88, #69, #103, #104, #105, #97, #106 ,version 0.10.2.8

[Feature] Code Analyze and Refactor 0.11 (#88)
[Feature] Mouse disturbing while using keys (#69)
[Feature] Reload menu when reenter or click (#103)
[BUG] Crash when fast mouse movings (#104)
[BUG] Loading was shown too often (#105)
[BUG] submenu wrong location in edgecase (#97)
[BUG] Folder shown as open (green) but is not open (#106)
This commit is contained in:
Markus Hofknecht 2020-06-20 17:38:21 +02:00
parent 1b683ff48a
commit d1b8c0b279
15 changed files with 901 additions and 988 deletions

File diff suppressed because it is too large Load diff

View file

@ -18,13 +18,15 @@ namespace SystemTrayMenu.Business
{
internal class Menus : IDisposable
{
internal event EventHandler<bool> LoadStarted;
internal event EventHandlerEmpty LoadStarted;
internal event EventHandlerEmpty LoadStopped;
private enum OpenCloseState { Default, Opening, Closing };
private OpenCloseState openCloseState = OpenCloseState.Default;
private readonly Menu[] menus = new Menu[MenuDefines.MenusMax];
private readonly BackgroundWorker worker = new BackgroundWorker();
private readonly BackgroundWorker workerMainMenu = new BackgroundWorker();
private readonly List<BackgroundWorker> workersSubMenu = new List<BackgroundWorker>();
private readonly WaitToLoadMenu waitToOpenMenu = new WaitToLoadMenu();
private readonly KeyboardInput keyboardInput;
private readonly Timer timerStillActiveCheck = new Timer();
private readonly WaitLeave waitLeave = new WaitLeave(MenuDefines.TimeUntilClose);
@ -35,27 +37,101 @@ namespace SystemTrayMenu.Business
public Menus()
{
worker.WorkerSupportsCancellation = true;
worker.DoWork += Load;
void Load(object sender, DoWorkEventArgs e)
workerMainMenu.WorkerSupportsCancellation = true;
workerMainMenu.DoWork += LoadMenu;
void LoadMenu(object senderDoWork, DoWorkEventArgs eDoWork)
{
e.Result = GetData((BackgroundWorker)sender, Config.Path, 0);
string path = Config.Path;
int level = 0;
RowData rowData = eDoWork.Argument as RowData;
if (rowData != null)
{
path = rowData.TargetFilePath;
level = rowData.MenuLevel + 1;
}
MenuData menuData = GetData((BackgroundWorker)senderDoWork, path, level);
menuData.RowDataParent = rowData;
eDoWork.Result = menuData;
}
worker.RunWorkerCompleted += LoadCompleted;
void LoadCompleted(object sender, RunWorkerCompletedEventArgs e)
workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted;
void LoadMainMenuCompleted(object sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped();
MenuData menuData = (MenuData)e.Result;
if (menuData.Validity == MenuDataValidity.Valid)
{
DisposeMenu(menus[0]);
DisposeMenu(menus[menuData.Level]);
menus[0] = Create(menuData, Path.GetFileName(Config.Path));
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
waitToOpenMenu.StopLoadMenu += WaitToOpenMenu_StopLoadMenu;
void WaitToOpenMenu_StopLoadMenu()
{
foreach (BackgroundWorker workerSubMenu in workersSubMenu.
Where(w => w.IsBusy))
{
workerSubMenu.CancelAsync();
}
}
waitToOpenMenu.StartLoadMenu += StartLoadMenu;
void StartLoadMenu(RowData rowData)
{
if (menus[0].IsUsable &&
menus[rowData.MenuLevel] == null ||
menus[rowData.MenuLevel].Tag as RowData != rowData)
{
LoadStarted();
BackgroundWorker workerSubMenu = workersSubMenu.
Where(w => !w.IsBusy).FirstOrDefault();
if (workerSubMenu == null)
{
workerSubMenu = new BackgroundWorker
{
WorkerSupportsCancellation = true
};
workerSubMenu.DoWork += LoadMenu;
workerSubMenu.RunWorkerCompleted += LoadSubMenuCompleted;
workersSubMenu.Add(workerSubMenu);
}
workerSubMenu.RunWorkerAsync(rowData); ;
}
void LoadSubMenuCompleted(object senderCompleted,
RunWorkerCompletedEventArgs e)
{
LoadStopped();
MenuData menuData = (MenuData)e.Result;
if (menus[0].IsUsable &&
menuData.Validity != MenuDataValidity.AbortedOrUnknown)
{
Menu menu = Create(menuData);
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
menu.SetTypeSub();
break;
case MenuDataValidity.Empty:
menu.SetTypeEmpty();
break;
case MenuDataValidity.NoAccess:
menu.SetTypeNoAccess();
break;
}
menu.Tag = menuData.RowDataParent;
menuData.RowDataParent.SubMenu = menu;
if (menus[0].IsUsable)
{
ShowSubMenu(menu);
}
}
}
}
keyboardInput = new KeyboardInput(menus);
keyboardInput.RegisterHotKey();
keyboardInput.HotKeyPressed += KeyboardInput_HotKeyPressed;
@ -65,12 +141,18 @@ namespace SystemTrayMenu.Business
}
keyboardInput.ClosePressed += MenusFadeOut;
keyboardInput.RowDeselected += CheckMenuOpenerStop;
keyboardInput.RowSelected += KeyboardInputRowSelected;
void KeyboardInputRowSelected(DataGridView dgv, int rowIndex)
keyboardInput.RowDeselected += waitToOpenMenu.RowDeselected;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
timerStillActiveCheck.Interval = 1000;
timerStillActiveCheck.Tick += StillActiveTick;
void StillActiveTick(object senderTimer, EventArgs eTimer)
{
FadeInIfNeeded();
CheckMenuOpenerStart(dgv, rowIndex);
if (!IsActive())
{
FadeHalfOrOutIfNeeded();
timerStillActiveCheck.Stop();
}
}
waitLeave.LeaveTriggered += LeaveTriggered;
@ -104,7 +186,6 @@ namespace SystemTrayMenu.Business
else
{
openCloseState = OpenCloseState.Opening;
LoadStarted(this, true);
StartWorker();
}
deactivatedTime = DateTime.MinValue;
@ -112,10 +193,9 @@ namespace SystemTrayMenu.Business
public void Dispose()
{
worker.Dispose();
workerMainMenu.Dispose();
keyboardInput.Dispose();
timerStillActiveCheck.Dispose();
waitLeave.Dispose();
IconReader.Dispose();
DisposeMenu(menus[0]);
}
@ -141,7 +221,7 @@ namespace SystemTrayMenu.Business
MenuData menuData = new MenuData
{
RowDatas = new List<RowData>(),
Validity = MenuDataValidity.Invalid,
Validity = MenuDataValidity.AbortedOrUnknown,
Level = level
};
if (!worker.CancellationPending)
@ -181,6 +261,7 @@ namespace SystemTrayMenu.Business
rowData.HiddenEntry = hiddenEntry;
string resolvedLnkPath = string.Empty;
rowData.ReadIcon(true, ref resolvedLnkPath);
rowData.MenuLevel = level;
menuData.RowDatas.Add(rowData);
}
}
@ -232,9 +313,16 @@ namespace SystemTrayMenu.Business
if (!worker.CancellationPending)
{
if (menuData.Validity == MenuDataValidity.Invalid)
if (menuData.Validity == MenuDataValidity.AbortedOrUnknown)
{
menuData.Validity = MenuDataValidity.Valid;
if (menuData.RowDatas.Count == 0)
{
menuData.Validity = MenuDataValidity.Empty;
}
else
{
menuData.Validity = MenuDataValidity.Valid;
}
}
}
@ -243,7 +331,7 @@ namespace SystemTrayMenu.Business
internal void MainPreload()
{
menus[0] = Create(GetData(worker, Config.Path, 0),
menus[0] = Create(GetData(workerMainMenu, Config.Path, 0),
Path.GetFileName(Config.Path));
menus[0].AdjustSizeAndLocation();
DisposeMenu(menus[0]);
@ -251,21 +339,19 @@ namespace SystemTrayMenu.Business
internal void StartWorker()
{
if (worker.IsBusy)
if (!workerMainMenu.IsBusy)
{
LoadStopped();
}
else
{
worker.RunWorkerAsync();
LoadStarted();
workerMainMenu.RunWorkerAsync(
new object[] { Config.Path, 0 });
}
}
internal void StopWorker()
{
if (worker.IsBusy)
if (workerMainMenu.IsBusy)
{
worker.CancelAsync();
workerMainMenu.CancelAsync();
}
}
@ -333,6 +419,7 @@ namespace SystemTrayMenu.Business
menu.MouseEnter += waitLeave.Stop;
menu.KeyPress += keyboardInput.KeyPress;
menu.CmdKeyProcessed += keyboardInput.CmdKeyProcessed;
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
menu.SearchTextChanging += keyboardInput.SearchTextChanging;
menu.SearchTextChanged += Menu_SearchTextChanged;
void Menu_SearchTextChanged(object sender, EventArgs e)
@ -358,33 +445,43 @@ namespace SystemTrayMenu.Business
{
menus[0].SetTitleColorActive();
AsList.ForEach(m => m.ShowWithFade());
}
CheckIfWindowsStartStoleFocusNoDeactivateInRareCase();
void CheckIfWindowsStartStoleFocusNoDeactivateInRareCase()
{
timerStillActiveCheck.Interval = 1000;
timerStillActiveCheck.Tick += StillActiveTick;
void StillActiveTick(object senderTimer, EventArgs eTimer)
{
if (!waitLeave.IsRunning)
{
FadeHalfOrOutIfNeeded();
if (!IsActive())
{
timerStillActiveCheck.Stop();
}
}
}
timerStillActiveCheck.Start();
}
}
menu.VisibleChanged += MenuVisibleChanged;
AddItemsToMenu(menuData.RowDatas, menu);
void AddItemsToMenu(List<RowData> data, Menu menu)
{
DataGridView dgv = menu.GetDataGridView();
DataTable dataTable = new DataTable();
dataTable.Columns.Add(dgv.Columns[0].Name, typeof(Icon));
dataTable.Columns.Add(dgv.Columns[1].Name, typeof(string));
dataTable.Columns.Add("data", typeof(RowData));
foreach (RowData rowData in data)
{
rowData.SetData(rowData, dataTable);
}
dgv.DataSource = dataTable;
}
DataGridView dgv = menu.GetDataGridView();
dgv.CellMouseEnter += waitToOpenMenu.MouseEnter;
dgv.CellMouseEnter += Dgv_CellMouseEnter;
dgv.CellMouseLeave += Dgv_CellMouseLeave;
void Dgv_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
if (menus[0].IsUsable)
{
if (keyboardInput.InUse)
{
keyboardInput.ClearIsSelectedByKey();
keyboardInput.InUse = false;
}
keyboardInput.Select(dgv, e.RowIndex);
}
}
dgv.CellMouseLeave += waitToOpenMenu.MouseLeave;
dgv.MouseMove += waitToOpenMenu.MouseMove;
dgv.MouseDown += Dgv_MouseDown;
dgv.MouseDoubleClick += Dgv_MouseDoubleClick;
dgv.SelectionChanged += Dgv_SelectionChanged;
@ -398,10 +495,6 @@ namespace SystemTrayMenu.Business
if (menu.IsUsable)
{
AdjustMenusSizeAndLocation();
if (menu.Level == 0)
{
menus[0].AdjustSizeAndLocation();
}
}
if (!menu.Visible)
{
@ -413,126 +506,6 @@ namespace SystemTrayMenu.Business
}
}
private void AddItemsToMenu(List<RowData> data, Menu menu)
{
DataGridView dgv = menu.GetDataGridView();
DataTable dataTable = new DataTable();
dataTable.Columns.Add(dgv.Columns[0].Name, typeof(Icon));
dataTable.Columns.Add(dgv.Columns[1].Name, typeof(string));
dataTable.Columns.Add("data", typeof(RowData));
foreach (RowData rowData in data)
{
CreateMenuRow(rowData, menu, dataTable);
}
dgv.DataSource = dataTable;
}
private void Dgv_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
if (menus[0].IsUsable)
{
if (keyboardInput.InUse)
{
CheckMenuOpenerStop(keyboardInput.iMenuKey,
keyboardInput.iRowKey);
keyboardInput.ClearIsSelectedByKey();
keyboardInput.InUse = false;
}
DataGridView dgv = (DataGridView)sender;
keyboardInput.Select(dgv, e.RowIndex);
CheckMenuOpenerStart(dgv, e.RowIndex);
}
}
private void CheckMenuOpenerStart(DataGridView dgv, int rowIndex)
{
if (rowIndex > -1 &&
dgv.Rows.Count > rowIndex)
{
RowData trigger = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
trigger.IsSelected = true;
dgv.Rows[rowIndex].Selected = true;
Menu menuFromTrigger = (Menu)dgv.FindForm();
Menu menuTriggered = trigger.SubMenu;
int level = menuFromTrigger.Level + 1;
if (trigger.ContainsMenu &&
level < MenuDefines.MenusMax &&
menus[0].IsUsable &&
(menus[level] == null ||
menus[level] != menuTriggered))
{
trigger.StopLoadMenuAndStartWaitToOpenIt();
trigger.StartMenuOpener();
if (trigger.Reading.IsBusy)
{
trigger.RestartLoading = true;
}
else
{
LoadStarted(this, false);
trigger.Reading.RunWorkerAsync(level);
}
}
}
}
private void CheckMenuOpenerStop(int menuIndex, int rowIndex, DataGridView dgv = null)
{
Menu menu = menus[menuIndex];
if (menu != null &&
rowIndex > -1)
{
if (dgv == null)
{
dgv = menu.GetDataGridView();
}
if (dgv.Rows.Count > rowIndex)
{
RowData trigger = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
if (trigger.Reading.IsBusy)
{
if (!trigger.IsContextMenuOpen)
{
trigger.IsSelected = false;
dgv.Rows[rowIndex].Selected = false;
}
trigger.Reading.CancelAsync();
}
else if (trigger.ContainsMenu && !trigger.IsLoading)
{
trigger.IsSelected = true;
dgv.Rows[rowIndex].Selected = true;
}
else
{
if (!trigger.IsContextMenuOpen)
{
trigger.IsSelected = false;
dgv.Rows[rowIndex].Selected = false;
}
}
if (trigger.IsLoading)
{
trigger.StopLoadMenuAndStartWaitToOpenIt();
trigger.IsLoading = false;
}
}
}
}
private void Dgv_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
if (!keyboardInput.InUse)
{
DataGridView dgv = (DataGridView)sender;
Menu menu = (Menu)dgv.FindForm();
CheckMenuOpenerStop(menu.Level, e.RowIndex, dgv);
}
}
private void Dgv_MouseDown(object sender, MouseEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
@ -541,8 +514,9 @@ namespace SystemTrayMenu.Business
if (hitTestInfo.RowIndex > -1 &&
dgv.Rows.Count > hitTestInfo.RowIndex)
{
RowData trigger = (RowData)dgv.Rows[hitTestInfo.RowIndex].Cells[2].Value;
trigger.MouseDown(dgv, e);
RowData rowData = (RowData)dgv.Rows[hitTestInfo.RowIndex].Cells[2].Value;
rowData.MouseDown(dgv, e);
waitToOpenMenu.ClickOpensInstantly(dgv, hitTestInfo.RowIndex);
}
}
@ -561,7 +535,11 @@ namespace SystemTrayMenu.Business
private void Dgv_SelectionChanged(object sender, EventArgs e)
{
DataGridView dgv = (DataGridView)sender;
RefreshSelection((DataGridView)sender);
}
private void RefreshSelection(DataGridView dgv)
{
foreach (DataGridViewRow row in dgv.Rows)
{
RowData rowData = (RowData)row.Cells[2].Value;
@ -573,14 +551,15 @@ namespace SystemTrayMenu.Business
else if (!menus[0].IsUsable)
{
row.DefaultCellStyle.SelectionBackColor = Color.White;
row.Selected = false;
}
else if (rowData.IsSelectedByKeyboard)
else if (rowData.IsSelected)
{
row.DefaultCellStyle.SelectionBackColor =
MenuDefines.ColorSelectedItem;
row.Selected = true;
}
else if (rowData.IsSelected)
else if (rowData.IsMenuOpen)
{
row.DefaultCellStyle.SelectionBackColor =
MenuDefines.ColorOpenFolder;
@ -588,93 +567,42 @@ namespace SystemTrayMenu.Business
}
else
{
rowData.IsSelected = false;
row.DefaultCellStyle.SelectionBackColor = Color.White;
row.Selected = false;
}
}
}
private void CreateMenuRow(RowData rowData, Menu menu, DataTable dataTable)
private void ShowSubMenu(Menu menuToShow)
{
rowData.SetData(rowData, dataTable);
rowData.OpenMenu += OpenSubMenu;
rowData.Reading.WorkerSupportsCancellation = true;
rowData.Reading.DoWork += ReadMenu_DoWork;
void ReadMenu_DoWork(object senderDoWork,
DoWorkEventArgs eDoWork)
//Clean up menu status IsMenuOpen for previous one
Menu menuPrevious = menus[menuToShow.Level - 1];
DataGridView dgvPrevious = menuPrevious.GetDataGridView();
foreach (DataRow row in ((DataTable)dgvPrevious.DataSource).Rows)
{
int level = (int)eDoWork.Argument;
BackgroundWorker worker = (BackgroundWorker)senderDoWork;
eDoWork.Result = Business.Menus.GetData(worker, rowData.TargetFilePath, level);
}
rowData.Reading.RunWorkerCompleted += ReadMenu_RunWorkerCompleted;
void ReadMenu_RunWorkerCompleted(object senderCompleted,
RunWorkerCompletedEventArgs e)
{
MenuData menuData = (MenuData)e.Result;
if (rowData.RestartLoading)
RowData rowDataToClear = (RowData)row[2];
if (rowDataToClear == (RowData)menuToShow.Tag)
{
rowData.RestartLoading = false;
rowData.Reading.RunWorkerAsync(menuData.Level);
rowDataToClear.IsMenuOpen = true;
}
else
{
LoadStopped();
if (menuData.Validity != MenuDataValidity.Invalid)
{
menu = Create(menuData);
if (menuData.RowDatas.Count > 0)
{
menu.SetTypeSub();
}
else if (menuData.Validity == MenuDataValidity.NoAccess)
{
menu.SetTypeNoAccess();
}
else
{
menu.SetTypeEmpty();
}
menu.Tag = rowData;
rowData.SubMenu = menu;
rowData.MenuLoaded();
}
rowDataToClear.IsMenuOpen = false;
}
}
}
RefreshSelection(dgvPrevious);
private void OpenSubMenu(object sender, RowData trigger)
{
Menu menuTriggered = trigger.SubMenu;
Menu menuFromTrigger = menus[menuTriggered.Level - 1];
for (int level = menuTriggered.Level;
level < MenuDefines.MenusMax; level++)
foreach (Menu menuToClose in menus.Where(
m => m != null && m.Level > menuPrevious.Level))
{
if (menus[level] != null)
{
Menu menuToClose = menus[level];
RowData oldTrigger = (RowData)menuToClose.Tag;
DataGridView dgv = menuFromTrigger.GetDataGridView();
foreach (DataGridViewRow row in dgv.Rows)
{
RowData rowData = (RowData)row.Cells[2].Value;
rowData.IsSelected = false;
}
trigger.IsSelected = true;
dgv.ClearSelection();
dgv.Rows[trigger.RowIndex].Selected = true;
menuToClose.HideWithFade();
menuToClose.VisibleChanged += MenuVisibleChanged;
menus[level] = null;
}
menuToClose.VisibleChanged += MenuVisibleChanged;
menuToClose.HideWithFade();
menus[menuToClose.Level] = null;
}
DisposeMenu(menus[menuTriggered.Level]);
menus[menuTriggered.Level] = menuTriggered;
menus[menuToShow.Level] = menuToShow;
AdjustMenusSizeAndLocation();
menus[menuTriggered.Level].ShowWithFadeOrTransparent(IsActive());
menus[menuToShow.Level].ShowWithFadeOrTransparent(IsActive());
}
private void FadeInIfNeeded()

View file

@ -1,76 +0,0 @@
using System;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
namespace SystemTrayMenu.Handler
{
internal class WaitMenuOpen : IDisposable
{
public event EventHandlerEmpty DoOpen;
private readonly Timer waitOpen = new Timer();
private bool waitedDone = false;
private bool clicked = false;
private bool menuLoaded = false;
public WaitMenuOpen()
{
waitOpen.Interval = MenuDefines.WaitMenuOpen;
waitOpen.Tick += WaitOpen_Tick;
}
private void WaitOpen_Tick(object sender, EventArgs e)
{
waitOpen.Stop();
waitedDone = true;
CheckConditionsToOpenMenu();
}
private void CheckConditionsToOpenMenu()
{
if ((waitedDone || clicked) &&
menuLoaded)
{
Stop();
DoOpen?.Invoke();
}
}
// When mouse on menu, wait x ms until open it
// meanwhile load content, click opens when loaded
// (to not interrupt user when he moves into a submenu)
public void Start()
{
if (!waitedDone)
{
waitOpen.Start();
}
}
public void Stop()
{
clicked = false;
waitedDone = false;
menuLoaded = false;
waitOpen.Stop();
}
public void Click()
{
clicked = true;
CheckConditionsToOpenMenu();
}
public void MenuLoaded()
{
menuLoaded = true;
CheckConditionsToOpenMenu();
}
public void Dispose()
{
Stop();
waitOpen.Dispose();
}
}
}

139
Business/WaitToLoadMenu.cs Normal file
View file

@ -0,0 +1,139 @@
using System;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.UserInterface;
using SystemTrayMenu.Utilities;
using Timer = System.Windows.Forms.Timer;
namespace SystemTrayMenu.Handler
{
internal class WaitToLoadMenu : IDisposable
{
internal event Action<RowData> StartLoadMenu;
internal event EventHandlerEmpty StopLoadMenu;
private readonly Timer timer = new Timer();
private DataGridView dgv = null;
private int rowIndex = 0;
private bool mouseActive = false;
private bool checkForMouseActive = false;
internal WaitToLoadMenu()
{
timer.Interval = 200;
timer.Tick += WaitOpen_Tick;
}
internal void MouseEnter(object sender, DataGridViewCellEventArgs e)
{
timer.Stop();
StopLoadMenu.Invoke();
SetData((DataGridView)sender, e.RowIndex);
checkForMouseActive = true;
timer.Start();
}
internal void RowSelected(DataGridView dgv, int rowIndex)
{
timer.Stop();
StopLoadMenu.Invoke();
SetData(dgv, rowIndex);
mouseActive = false;
checkForMouseActive = false;
timer.Start();
}
internal void MouseLeave(object sender, DataGridViewCellEventArgs e)
{
timer.Stop();
StopLoadMenu.Invoke();
ResetData((DataGridView)sender, e.RowIndex);
}
internal void RowDeselected(int iMenuBefore, int rowIndex, DataGridView dgv) //iMenuBefore not needed
{
timer.Stop();
StopLoadMenu.Invoke();
ResetData(dgv, rowIndex);
mouseActive = false;
}
internal void ClickOpensInstantly(DataGridView dgv, int rowIndex)
{
timer.Stop();
StopLoadMenu.Invoke();
SetData(dgv, rowIndex);
mouseActive = true;
checkForMouseActive = false;
CallOpenMenuNow();
}
internal void EnterOpensInstantly(DataGridView dgv, int rowIndex)
{
timer.Stop();
StopLoadMenu.Invoke();
SetData(dgv, rowIndex);
mouseActive = false;
checkForMouseActive = false;
CallOpenMenuNow();
}
internal void MouseMove(object sender, MouseEventArgs e)
{
mouseActive = true;
}
private void WaitOpen_Tick(object sender, EventArgs e)
{
timer.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.MenuLevel = menu.Level;
if (!rowData.IsContextMenuOpen &&
rowData.ContainsMenu &&
rowData.MenuLevel < MenuDefines.MenusMax)
{
StartLoadMenu.Invoke(rowData);
}
}
}
private void SetData(DataGridView dgv, int rowIndex)
{
this.dgv = dgv;
this.rowIndex = rowIndex;
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
rowData.IsSelected = true;
dgv.Rows[rowIndex].Selected = true;
}
private void ResetData(DataGridView dgv, int rowIndex)
{
if (dgv != null)
{
RowData rowData = (RowData)dgv.Rows[rowIndex].Cells[2].Value;
rowData.IsSelected = false;
dgv.Rows[rowIndex].Selected = false;
this.dgv = null;
this.rowIndex = 0;
}
}
public void Dispose()
{
timer.Stop();
timer.Dispose();
}
}
}

View file

@ -1,6 +1,4 @@
//using Microsoft.WindowsAPICodePack.Dialogs;
using System;
using System.Diagnostics;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

View file

@ -14,11 +14,11 @@ namespace SystemTrayMenu
internal static readonly Color ColorTitleSelected = AppColors.Yellow;
internal static readonly Color ColorTitleBackground = AppColors.Azure;
internal const int KeySearchInterval = 1000;
internal const int LengthMax = 37;
internal const int Scrollspeed = 4;
internal const int WaitMenuOpen = 200;
internal const int MenusMax = 50;
internal const int TimeUntilClose = 1000;
internal const int MenusMax = 50;
internal const int LengthMax = 37;
internal static float MaxMenuWidth = 300;
}
internal static class AppColors

View file

@ -4,15 +4,17 @@ namespace SystemTrayMenu.DataClasses
{
internal enum MenuDataValidity
{
AbortedOrUnknown,
Valid,
Invalid,
Empty,
NoAccess
}
internal struct MenuData
{
public List<RowData> RowDatas;
public MenuDataValidity Validity;
public int Level;
internal List<RowData> RowDatas;
internal MenuDataValidity Validity;
internal int Level;
internal RowData RowDataParent;
};
}

View file

@ -10,7 +10,6 @@ using System.Linq;
using System.Security;
using System.Text;
using System.Windows.Forms;
using SystemTrayMenu.Handler;
using SystemTrayMenu.Utilities;
using TAFactory.IconPack;
using Menu = SystemTrayMenu.UserInterface.Menu;
@ -19,18 +18,14 @@ namespace SystemTrayMenu.DataClasses
{
internal class RowData : IDisposable
{
internal event EventHandler<RowData> OpenMenu;
internal BackgroundWorker Reading = new BackgroundWorker();
internal FileInfo FileInfo;
internal Menu SubMenu;
internal bool IsMenuOpen;
internal bool IsSelected;
internal bool IsSelectedByKeyboard;
internal bool ContainsMenu;
internal bool IsContextMenuOpen;
private static DateTime ContextMenuClosed;
internal bool IsResolvedLnk;
internal bool IsLoading = false;
internal bool RestartLoading = false;
internal bool HiddenEntry;
internal string TargetFilePath;
internal string TargetFilePathOrig;
@ -38,23 +33,17 @@ namespace SystemTrayMenu.DataClasses
private string WorkingDirectory;
private string Arguments;
private string Text;
private readonly WaitMenuOpen waitMenuOpen = new WaitMenuOpen();
private Icon Icon = null;
private bool diposeIcon = true;
private bool isDisposed = false;
internal int MenuLevel;
internal RowData()
{
Reading.WorkerSupportsCancellation = true;
waitMenuOpen.DoOpen += WaitMenuOpen_DoOpen;
}
internal void SetText(string text)
{
if (text.Length > MenuDefines.LengthMax)
{
text = $"{text.Substring(0, MenuDefines.LengthMax)}...";
}
Text = text;
}
@ -295,16 +284,6 @@ namespace SystemTrayMenu.DataClasses
internal void MouseDown(DataGridView dgv, MouseEventArgs e)
{
if (ContainsMenu)
{
TriggerMenuOpener(); // Touchscreen
}
if (IsLoading)
{
waitMenuOpen.Click();
}
if (e != null &&
e.Button == MouseButtons.Right &&
FileInfo != null &&
@ -381,43 +360,6 @@ namespace SystemTrayMenu.DataClasses
}
}
internal void MenuLoaded()
{
waitMenuOpen.MenuLoaded();
}
internal void StartMenuOpener()
{
if (ContainsMenu)
{
IsLoading = true;
waitMenuOpen.Start();
}
}
private void TriggerMenuOpener()
{
if (ContainsMenu && IsLoading)
{
waitMenuOpen.Start();
}
}
internal void StopLoadMenuAndStartWaitToOpenIt()
{
if (ContainsMenu)
{
waitMenuOpen.Stop();
//IsLoading = false;
}
}
private void WaitMenuOpen_DoOpen()
{
IsLoading = false;
OpenMenu?.Invoke(this, this);
}
public void Dispose()
{
Dispose(true);
@ -428,8 +370,6 @@ namespace SystemTrayMenu.DataClasses
{
if (!isDisposed)
{
waitMenuOpen.Dispose();
Reading.Dispose();
if (diposeIcon)
{
Icon?.Dispose();

View file

@ -35,5 +35,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("0.10.2.7")]
[assembly: AssemblyFileVersion("0.10.2.7")]
[assembly: AssemblyVersion("0.10.2.8")]
[assembly: AssemblyFileVersion("0.10.2.8")]

View file

@ -20,7 +20,7 @@ namespace SystemTrayMenu.UserInterface
private const int Interval60FPS = 16; //60fps=>1s/60fps=~16.6ms
private readonly NotifyIcon notifyIcon = new NotifyIcon();
private DateTime timeLoadingStart;
private int threadsLoading = 0;
private bool threadsLoading = false;
private readonly Timer load = new Timer();
private int loadCount = 0;
private readonly int indexLoad = 0;
@ -85,36 +85,21 @@ namespace SystemTrayMenu.UserInterface
load.Dispose();
}
public void LoadingStart(object sender = null, bool reset = false)
public void LoadingStart()
{
if (reset)
{
threadsLoading = 0;
}
timeLoadingStart = DateTime.Now;
threadsLoading++;
threadsLoading = true;
load.Start();
}
public void LoadingStop()
{
threadsLoading--;
threadsLoading = false;
}
// Show a static icon when mainthread blocked
//public void LoadingStaticWait()
//{
// notifyIcon.Icon = bitmapsLoading[loadCount++ % indexLoad];
//}
//public void LoadingStaticStop()
//{
// notifyIcon.Icon = R.SystemTrayMenu;
//}
private void Load_Tick(object sender, EventArgs e)
{
if (threadsLoading > 0)
if (threadsLoading)
{
if (DateTime.Now - timeLoadingStart > new TimeSpan(0, 0, 0, 0, 500))
{

View file

@ -42,33 +42,30 @@ namespace SystemTrayMenu.UserInterface.FolderDialog
}
public DialogResult ShowVistaDialog(IWin32Window owner)
{
var frm = (NativeMethods.IFileDialog)(new NativeMethods.FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
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 (this.InitialFolder != null)
if (InitialFolder != null)
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName
(this.InitialFolder, IntPtr.Zero, ref riid,
out directoryShellItem) == NativeMethods.S_OK)
(InitialFolder, IntPtr.Zero, ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (this.DefaultFolder != null)
if (DefaultFolder != null)
{
NativeMethods.IShellItem directoryShellItem;
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
Guid riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName
(this.DefaultFolder, IntPtr.Zero, ref riid,
out directoryShellItem) == NativeMethods.S_OK)
(DefaultFolder, IntPtr.Zero, ref riid,
out NativeMethods.IShellItem directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
@ -76,18 +73,16 @@ namespace SystemTrayMenu.UserInterface.FolderDialog
if (frm.Show(owner.Handle) == NativeMethods.S_OK)
{
NativeMethods.IShellItem shellItem;
if (frm.GetResult(out shellItem) == NativeMethods.S_OK)
if (frm.GetResult(out NativeMethods.IShellItem shellItem) == NativeMethods.S_OK)
{
IntPtr pszString;
if (shellItem.GetDisplayName(NativeMethods.SIGDN_FILESYSPATH,
out pszString) == NativeMethods.S_OK)
out IntPtr pszString) == NativeMethods.S_OK)
{
if (pszString != IntPtr.Zero)
{
try
{
this.Folder = Marshal.PtrToStringAuto(pszString);
Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
@ -102,20 +97,20 @@ namespace SystemTrayMenu.UserInterface.FolderDialog
}
public DialogResult ShowLegacyDialog(IWin32Window owner)
{
using (var frm = new SaveFileDialog())
using (SaveFileDialog frm = new SaveFileDialog())
{
frm.CheckFileExists = false;
frm.CheckPathExists = true;
frm.CreatePrompt = false;
frm.Filter = "|" + Guid.Empty.ToString();
frm.FileName = "any";
if (this.InitialFolder != null) { frm.InitialDirectory = this.InitialFolder; }
if (InitialFolder != null) { frm.InitialDirectory = InitialFolder; }
frm.OverwritePrompt = false;
frm.Title = "Select Folder";
frm.ValidateNames = false;
if (frm.ShowDialog(owner) == DialogResult.OK)
{
this.Folder = Path.GetDirectoryName(frm.FileName);
Folder = Path.GetDirectoryName(frm.FileName);
return DialogResult.OK;
}
else
@ -154,12 +149,9 @@ namespace SystemTrayMenu.UserInterface.FolderDialog
/// <summary>
/// Original ptr
/// </summary>
public IntPtr Handle
{
get { return _hwnd; }
}
public IntPtr Handle => _hwnd;
private IntPtr _hwnd;
private readonly IntPtr _hwnd;
}
internal static class NativeMethods
{

View file

@ -174,6 +174,7 @@
this.textBoxSearch.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold);
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.ShortcutsEnabled = false;
this.textBoxSearch.Size = new System.Drawing.Size(55, 15);

View file

@ -20,7 +20,6 @@ namespace SystemTrayMenu.UserInterface
internal event EventHandler<Keys> CmdKeyProcessed;
internal event EventHandlerEmpty SearchTextChanging;
internal event EventHandler SearchTextChanged;
#warning #68 => use event and not a action here?
internal bool IsUsable => Visible && !fading.IsHiding &&
!IsDisposed && !Disposing;
@ -158,23 +157,23 @@ namespace SystemTrayMenu.UserInterface
case MenuType.Empty:
SetTitle(Translator.GetText("Folder empty"));
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
pictureBoxSearch.Visible = false;
textBoxSearch.Visible = false;
tableLayoutPanelSearch.Visible = false;
break;
case MenuType.NoAccess:
SetTitle(Translator.GetText("Folder inaccessible"));
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
pictureBoxSearch.Visible = false;
textBoxSearch.Visible = false;
tableLayoutPanelSearch.Visible = false;
break;
case MenuType.MaxReached:
SetTitle($"Max {MenuDefines.MenusMax - 1} Menus");
labelTitle.BackColor = MenuDefines.ColorTitleWarning;
this.pictureBoxSearch.Visible = false;
this.textBoxSearch.Visible = false;
this.tableLayoutPanelSearch.Visible = false;
pictureBoxSearch.Visible = false;
textBoxSearch.Visible = false;
tableLayoutPanelSearch.Visible = false;
break;
case MenuType.Main:
break;
@ -275,13 +274,15 @@ namespace SystemTrayMenu.UserInterface
{
if (directionToRight)
{
x = menuPredecessor.Location.X + Width -
x = menuPredecessor.Location.X +
menuPredecessor.Width -
(int)Math.Round(Scaling.Factor, 0,
MidpointRounding.AwayFromZero);
}
else
{
x = menuPredecessor.Location.X - Width +
x = menuPredecessor.Location.X -
Width +
(int)Math.Round(Scaling.Factor, 0,
MidpointRounding.AwayFromZero);
}
@ -302,17 +303,17 @@ namespace SystemTrayMenu.UserInterface
{
RowData trigger = (RowData)Tag;
DataGridView dgv = menuPredecessor.GetDataGridView();
int distanceToDgvTop = 0;
int distanceFromItemToDgvTop = 0;
if (dgv.Rows.Count > trigger.RowIndex)
{
Rectangle cellRectangle = dgv.GetCellDisplayRectangle(
0, trigger.RowIndex, false);
distanceToDgvTop = cellRectangle.Top;
distanceFromItemToDgvTop = cellRectangle.Top;
}
y = menuPredecessor.Location.Y +
menuPredecessor.dgv.Location.Y +
distanceToDgvTop;
if ((y + Height) > dgvHeightMax)
distanceFromItemToDgvTop;
if ((y + Height - tableLayoutPanelSearch.Height) > dgvHeightMax)
{
y = dgvHeightMax - Height + menuRestNeeded;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

View file

@ -31,6 +31,10 @@ namespace SystemTrayMenu.Utilities
widthMax = checkWidth;
}
}
if (widthMax > MenuDefines.MaxMenuWidth)
{
widthMax = MenuDefines.MaxMenuWidth;
}
dgv.Columns[i].Width = (int)(widthMax + 0.5);
string stringWithWidthLikeIcon = "____";