//
// Copyright (c) PlaceholderCompany. All rights reserved.
//
namespace SystemTrayMenu.Business
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using SystemTrayMenu.DataClasses;
using SystemTrayMenu.Handler;
using SystemTrayMenu.Helper;
using SystemTrayMenu.Utilities;
using Menu = SystemTrayMenu.UserInterface.Menu;
using Timer = System.Windows.Forms.Timer;
internal class Menus : IDisposable
{
private readonly Menu[] menus = new Menu[MenuDefines.MenusMax];
private readonly BackgroundWorker workerMainMenu = new();
private readonly List workersSubMenu = new();
private readonly DgvMouseRow dgvMouseRow = new();
private readonly WaitToLoadMenu waitToOpenMenu = new();
private readonly KeyboardInput keyboardInput;
private readonly Timer timerShowProcessStartedAsLoadingIcon = new();
private readonly Timer timerStillActiveCheck = new();
private readonly WaitLeave waitLeave = new(Properties.Settings.Default.TimeUntilCloses);
private DateTime deactivatedTime = DateTime.MinValue;
private DateTime dateTimeLastOpening = DateTime.MinValue;
private DateTime dateTimeDisplaySettingsChanged = DateTime.MinValue;
private OpenCloseState openCloseState = OpenCloseState.Default;
private bool showingMessageBox;
private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position;
private bool searchTextChanging;
private bool waitingForReactivate;
private int rowIndexLastMouseDown = -1;
private bool showMenuAfterMainPreload;
public Menus()
{
workerMainMenu.WorkerSupportsCancellation = true;
workerMainMenu.DoWork += LoadMenu;
workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted;
void LoadMainMenuCompleted(object sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped();
if (e.Result == null)
{
// Clean up menu status IsMenuOpen for previous one
DataGridView dgvMainMenu = menus[0].GetDataGridView();
foreach (DataRow row in ((DataTable)dgvMainMenu.DataSource).Rows)
{
RowData rowDataToClear = (RowData)row[2];
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
RefreshSelection(dgvMainMenu);
if (Properties.Settings.Default.RefreshLocationEachTime)
{
menus[0].Tag = null;
}
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
menus[0].ResetSearchText();
}
else
{
MenuData menuData = (MenuData)e.Result;
switch (menuData.Validity)
{
case MenuDataValidity.Valid:
if (Properties.Settings.Default.CacheMainMenu)
{
if (IconReader.MainPreload)
{
workerMainMenu.DoWork -= LoadMenu;
menus[0] = Create(menuData, Path.GetFileName(Config.Path));
IconReader.MainPreload = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
DisposeMenu(menus[menuData.Level]);
menus[0] = Create(menuData, Path.GetFileName(Config.Path));
if (IconReader.MainPreload)
{
IconReader.MainPreload = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
break;
case MenuDataValidity.Empty:
if (!showingMessageBox)
{
showingMessageBox = true;
MessageBox.Show(Translator.GetText(
"MessageRootFolderEmpty"));
OpenFolder();
Config.SetFolderByUser();
showingMessageBox = false;
}
break;
case MenuDataValidity.NoAccess:
if (!showingMessageBox)
{
showingMessageBox = true;
MessageBox.Show(Translator.GetText(
"MessageRootFolderNoAccess"));
OpenFolder();
Config.SetFolderByUser();
showingMessageBox = false;
}
break;
case MenuDataValidity.AbortedOrUnknown:
Log.Info("MenuDataValidity.AbortedOrUnknown");
break;
default:
break;
}
}
openCloseState = OpenCloseState.Default;
}
waitToOpenMenu.StopLoadMenu += WaitToOpenMenu_StopLoadMenu;
void WaitToOpenMenu_StopLoadMenu()
{
foreach (BackgroundWorker workerSubMenu in workersSubMenu.
Where(w => w.IsBusy))
{
workerSubMenu.CancelAsync();
}
LoadStopped();
}
waitToOpenMenu.StartLoadMenu += StartLoadMenu;
void StartLoadMenu(RowData rowData)
{
if (menus[0].IsUsable &&
(menus[rowData.MenuLevel + 1] == null ||
menus[rowData.MenuLevel + 1].Tag as RowData != rowData))
{
CreateAndShowLoadingMenu(rowData);
void CreateAndShowLoadingMenu(RowData rowData)
{
MenuData menuDataLoading = new()
{
RowDatas = new List(),
Validity = MenuDataValidity.Valid,
Level = rowData.MenuLevel + 1,
};
Menu menuLoading = Create(menuDataLoading, Path.GetFileName(Config.Path));
menuLoading.IsLoadingMenu = true;
AdjustMenusSizeAndLocation();
menus[rowData.MenuLevel + 1] = menuLoading;
menuLoading.Tag = menuDataLoading.RowDataParent = rowData;
menuDataLoading.RowDataParent.SubMenu = menuLoading;
menuLoading.SetTypeLoading();
ShowSubMenu(menuLoading);
}
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)
{
MenuData menuData = (MenuData)e.Result;
Menu menuLoading = menus[menuData.Level];
if (menuLoading != null && menuLoading.IsLoadingMenu)
{
menuLoading.HideWithFade();
menus[menuLoading.Level] = null;
}
if (menuData.Validity != MenuDataValidity.AbortedOrUnknown &&
menus[0].IsUsable)
{
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);
}
}
}
}
waitToOpenMenu.CloseMenu += CloseMenu;
void CloseMenu(int level)
{
if (level < menus.Length && menus[level] != null)
{
HideOldMenu(menus[level]);
}
if (level - 1 < menus.Length && menus[level - 1] != null)
{
menus[level - 1].FocusTextBox();
}
}
waitToOpenMenu.MouseEnterOk += MouseEnterOk;
void MouseEnterOk(DataGridView dgv, int rowIndex)
{
if (menus[0].IsUsable)
{
if (keyboardInput.InUse)
{
keyboardInput.ClearIsSelectedByKey();
keyboardInput.InUse = false;
}
keyboardInput.Select(dgv, rowIndex, false);
}
}
dgvMouseRow.RowMouseEnter += waitToOpenMenu.MouseEnter;
dgvMouseRow.RowMouseLeave += waitToOpenMenu.MouseLeave;
dgvMouseRow.RowMouseLeave += Dgv_RowMouseLeave;
keyboardInput = new KeyboardInput(menus);
keyboardInput.RegisterHotKey();
keyboardInput.HotKeyPressed += () => SwitchOpenClose(false);
keyboardInput.ClosePressed += MenusFadeOut;
keyboardInput.RowDeselected += waitToOpenMenu.RowDeselected;
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
keyboardInput.RowSelected += AdjustScrollbarToDisplayedRow;
void AdjustScrollbarToDisplayedRow(DataGridView dgv, int index)
{
Menu menu = (Menu)dgv.FindForm();
menu.AdjustScrollbar();
}
timerShowProcessStartedAsLoadingIcon.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed;
timerStillActiveCheck.Interval = Properties.Settings.Default.TimeUntilClosesAfterEnterPressed + 20;
timerStillActiveCheck.Tick += (sender, e) => StillActiveTick();
void StillActiveTick()
{
if (!IsActive())
{
FadeHalfOrOutIfNeeded();
}
timerStillActiveCheck.Stop();
}
waitLeave.LeaveTriggered += FadeHalfOrOutIfNeeded;
}
internal event EventHandlerEmpty LoadStarted;
internal event EventHandlerEmpty LoadStopped;
private enum OpenCloseState
{
Default,
Opening,
Closing,
}
private IEnumerable