Improve window size and position calculations

Fix several warnings
This commit is contained in:
Peter Kirmeier 2023-04-16 20:17:24 +02:00
parent b12d4ad656
commit c9ce4d1d21
5 changed files with 189 additions and 157 deletions

View file

@ -16,13 +16,13 @@ namespace SystemTrayMenu.Handler
internal class KeyboardInput : IDisposable internal class KeyboardInput : IDisposable
{ {
private readonly Menu[] menus; private readonly Menu?[] menus;
private readonly KeyboardHook hook = new(); private readonly KeyboardHook hook = new();
private int iRowKey = -1; private int iRowKey = -1;
private int iMenuKey; private int iMenuKey;
public KeyboardInput(Menu[] menus) public KeyboardInput(Menu?[] menus)
{ {
this.menus = menus; this.menus = menus;
} }

View file

@ -27,7 +27,7 @@ namespace SystemTrayMenu.Business
internal class Menus : IDisposable internal class Menus : IDisposable
{ {
private readonly Dispatcher dispatchter = Dispatcher.CurrentDispatcher; private readonly Dispatcher dispatchter = Dispatcher.CurrentDispatcher;
private readonly Menu[] menus = new Menu[MenuDefines.MenusMax]; private readonly Menu?[] menus = new Menu?[MenuDefines.MenusMax];
private readonly BackgroundWorker workerMainMenu = new(); private readonly BackgroundWorker workerMainMenu = new();
private readonly List<BackgroundWorker> workersSubMenu = new(); private readonly List<BackgroundWorker> workersSubMenu = new();
private readonly DgvMouseRow<ListView> dgvMouseRow = new(); private readonly DgvMouseRow<ListView> dgvMouseRow = new();
@ -43,18 +43,25 @@ namespace SystemTrayMenu.Business
private OpenCloseState openCloseState = OpenCloseState.Default; private OpenCloseState openCloseState = OpenCloseState.Default;
private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position; private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position;
private bool searchTextChanging; private bool searchTextChanging;
private bool waitingForReactivate;
private int lastMouseDownRowIndex = -1; private int lastMouseDownRowIndex = -1;
private bool showMenuAfterMainPreload; private bool showMenuAfterMainPreload;
#if TODO // TOUCH #if TODO // TOUCH
private int dragSwipeScrollingStartRowIndex = -1; private int dragSwipeScrollingStartRowIndex = -1;
#endif
private bool isDraggingSwipeScrolling; private bool isDraggingSwipeScrolling;
#endif
private bool isDragSwipeScrolled; private bool isDragSwipeScrolled;
private bool hideSubmenuDuringRefreshSearch; private bool hideSubmenuDuringRefreshSearch;
public Menus() public Menus()
{ {
keyboardInput = new(menus);
keyboardInput.RegisterHotKey();
keyboardInput.HotKeyPressed += () => SwitchOpenClose(false);
keyboardInput.ClosePressed += MenusFadeOut;
keyboardInput.RowDeselected += waitToOpenMenu.RowDeselected;
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
workerMainMenu.WorkerSupportsCancellation = true; workerMainMenu.WorkerSupportsCancellation = true;
workerMainMenu.DoWork += LoadMenu; workerMainMenu.DoWork += LoadMenu;
workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted; workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted;
@ -67,7 +74,7 @@ namespace SystemTrayMenu.Business
{ {
// The main menu gets loaded again // The main menu gets loaded again
// Clean up menu status of previous one // Clean up menu status of previous one
ListView? dgvMainMenu = menus[0].GetDataGridView(); ListView? dgvMainMenu = menus[0]?.GetDataGridView();
if (dgvMainMenu != null) if (dgvMainMenu != null)
{ {
foreach (ListViewItemData item in dgvMainMenu.Items) foreach (ListViewItemData item in dgvMainMenu.Items)
@ -84,7 +91,11 @@ namespace SystemTrayMenu.Business
if (Settings.Default.AppearAtMouseLocation) if (Settings.Default.AppearAtMouseLocation)
{ {
menus[0].RowDataParent = null; Menu? menu = menus[0];
if (menu != null)
{
menu.RowDataParent = null;
}
} }
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); }); AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
@ -151,9 +162,9 @@ namespace SystemTrayMenu.Business
waitToOpenMenu.StartLoadMenu += StartLoadMenu; waitToOpenMenu.StartLoadMenu += StartLoadMenu;
void StartLoadMenu(RowData rowData) void StartLoadMenu(RowData rowData)
{ {
if (menus[0].IsUsable && if (IsMainUsable && rowData.Path != null &&
(menus[rowData.Level + 1] == null || (menus[rowData.Level + 1] == null ||
menus[rowData.Level + 1].RowDataParent != rowData)) menus[rowData.Level + 1]?.RowDataParent != rowData))
{ {
Create(new(rowData.Level + 1, rowData), rowData.Path); // Level 1+ Sub Menu (loading) Create(new(rowData.Level + 1, rowData), rowData.Path); // Level 1+ Sub Menu (loading)
@ -187,27 +198,31 @@ namespace SystemTrayMenu.Business
return; return;
} }
if (menus[0].IsUsable) if (IsMainUsable)
{ {
if (menuData.DirectoryState != MenuDataDirectoryState.Undefined) if (menuData.DirectoryState != MenuDataDirectoryState.Undefined)
{ {
// Sub Menu (completed) // Sub Menu (completed)
menu.AddItemsToMenu(menuData.RowDatas); menu.AddItemsToMenu(menuData.RowDatas);
menu.SetSubMenuState(menuData.DirectoryState); menu.SetSubMenuState(menuData.DirectoryState);
AdjustMenusSizeAndLocation(); AdjustMenusSizeAndLocation(menu.Level);
} }
else else
{ {
menu.HideWithFade(); menu.HideWithFade();
menus[menu.Level] = null; menus[menu.Level] = null;
if (menuData.RowDataParent != null)
{
menuData.RowDataParent.IsMenuOpen = false; menuData.RowDataParent.IsMenuOpen = false;
menuData.RowDataParent.IsClicking = false; menuData.RowDataParent.IsClicking = false;
menuData.RowDataParent.IsSelected = false; menuData.RowDataParent.IsSelected = false;
Menu menuPrevious = menus[menuData.Level - 1]; }
if (menuPrevious != null)
ListView? lv = menus[menuData.Level - 1]?.GetDataGridView();
if (lv != null)
{ {
RefreshSelection(menuPrevious.GetDataGridView()); RefreshSelection(lv);
} }
} }
} }
@ -217,14 +232,18 @@ namespace SystemTrayMenu.Business
waitToOpenMenu.CloseMenu += CloseMenu; waitToOpenMenu.CloseMenu += CloseMenu;
void CloseMenu(int level) void CloseMenu(int level)
{ {
if (level < menus.Length && menus[level] != null) if (level < menus.Length)
{ {
HideOldMenu(menus[level]); Menu? menu = menus[level];
if (menu != null)
{
HideOldMenu(menu);
}
} }
if (level - 1 < menus.Length && menus[level - 1] != null) if (level - 1 < menus.Length && menus[level - 1] != null)
{ {
menus[level - 1].FocusTextBox(); menus[level - 1]?.FocusTextBox();
} }
} }
@ -235,16 +254,8 @@ namespace SystemTrayMenu.Business
dgvMouseRow.RowMouseLeave += Dgv_RowMouseLeave; dgvMouseRow.RowMouseLeave += Dgv_RowMouseLeave;
#endif #endif
keyboardInput = new(menus);
keyboardInput.RegisterHotKey();
keyboardInput.HotKeyPressed += () => SwitchOpenClose(false);
keyboardInput.ClosePressed += MenusFadeOut;
keyboardInput.RowDeselected += waitToOpenMenu.RowDeselected;
keyboardInput.EnterPressed += waitToOpenMenu.EnterOpensInstantly;
keyboardInput.RowSelected += waitToOpenMenu.RowSelected;
joystickHelper = new(); joystickHelper = new();
joystickHelper.KeyPressed += (key, modifiers) => menus[0].Dispatcher.Invoke(keyboardInput.CmdKeyProcessed, new object[] { null!, key, modifiers }); joystickHelper.KeyPressed += (key, modifiers) => menus[0]?.Dispatcher.Invoke(keyboardInput.CmdKeyProcessed, new object[] { null!, key, modifiers });
timerShowProcessStartedAsLoadingIcon.Interval = TimeSpan.FromMilliseconds(Settings.Default.TimeUntilClosesAfterEnterPressed); timerShowProcessStartedAsLoadingIcon.Interval = TimeSpan.FromMilliseconds(Settings.Default.TimeUntilClosesAfterEnterPressed);
timerStillActiveCheck.Interval = TimeSpan.FromMilliseconds(Settings.Default.TimeUntilClosesAfterEnterPressed + 20); timerStillActiveCheck.Interval = TimeSpan.FromMilliseconds(Settings.Default.TimeUntilClosesAfterEnterPressed + 20);
@ -313,7 +324,9 @@ namespace SystemTrayMenu.Business
Closing, Closing,
} }
private IEnumerable<Menu> AsEnumerable => menus.Where(m => m != null && !m.IsDisposed); private bool IsMainUsable => menus[0]?.IsUsable ?? false;
private IEnumerable<Menu> AsEnumerable => menus.Where(m => m != null && !m.IsDisposed) !;
private List<Menu> AsList => AsEnumerable.ToList(); private List<Menu> AsList => AsEnumerable.ToList();
@ -387,8 +400,11 @@ namespace SystemTrayMenu.Business
{ {
// Case when Folder Dialog open // Case when Folder Dialog open
} }
else if (openCloseState == OpenCloseState.Opening || else
(menus[0] != null && menus[0].Visibility == Visibility.Visible && openCloseState == OpenCloseState.Default)) {
Menu? menu = menus[0];
if (openCloseState == OpenCloseState.Opening ||
(menu != null && menu.Visibility == Visibility.Visible && openCloseState == OpenCloseState.Default))
{ {
openCloseState = OpenCloseState.Closing; openCloseState = OpenCloseState.Closing;
MenusFadeOut(); MenusFadeOut();
@ -404,6 +420,7 @@ namespace SystemTrayMenu.Business
joystickHelper.Enable(); joystickHelper.Enable();
StartWorker(); StartWorker();
} }
}
deactivatedTime = DateTime.MinValue; deactivatedTime = DateTime.MinValue;
} }
@ -485,9 +502,9 @@ namespace SystemTrayMenu.Business
{ {
bool IsShellContextMenuOpen() bool IsShellContextMenuOpen()
{ {
foreach (Menu menu in menus.Where(m => m != null)) foreach (Menu? menu in menus.Where(m => m != null))
{ {
ListView? dgv = menu.GetDataGridView(); ListView? dgv = menu?.GetDataGridView();
if (dgv != null) if (dgv != null)
{ {
foreach (ListViewItemData item in dgv.Items) foreach (ListViewItemData item in dgv.Items)
@ -504,7 +521,7 @@ namespace SystemTrayMenu.Business
return false; return false;
} }
foreach (Menu menu in menus.Where(m => m != null && m.IsActive)) foreach (Menu? menu in menus.Where(m => m != null && m.IsActive))
{ {
return true; return true;
} }
@ -516,7 +533,7 @@ namespace SystemTrayMenu.Business
{ {
Menu menu = new(menuData, path); Menu menu = new(menuData, path);
menu.MenuScrolled += AdjustMenusSizeAndLocation; // TODO: Only update vertical location while scrolling? menu.MenuScrolled += () => AdjustMenusSizeAndLocation(menu.Level + 1); // TODO: Only update vertical location while scrolling?
menu.MouseLeave += (_, _) => menu.MouseLeave += (_, _) =>
{ {
// Restart timer // Restart timer
@ -529,15 +546,38 @@ namespace SystemTrayMenu.Business
menu.KeyPressCheck += Menu_KeyPressCheck; menu.KeyPressCheck += Menu_KeyPressCheck;
#endif #endif
menu.SearchTextChanging += Menu_SearchTextChanging; menu.SearchTextChanging += Menu_SearchTextChanging;
#if TODO // SEARCH void Menu_SearchTextChanging()
{
searchTextChanging = true;
keyboardInput.SearchTextChanging();
waitToOpenMenu.MouseActive = false;
}
menu.SearchTextChanged += Menu_SearchTextChanged; menu.SearchTextChanged += Menu_SearchTextChanged;
#endif void Menu_SearchTextChanged(Menu menu, bool isSearchStringEmpty)
{
keyboardInput.SearchTextChanged(menu, isSearchStringEmpty);
AdjustMenusSizeAndLocation(menu.Level + 1);
searchTextChanging = false;
// if any open menu close
if (menu.Level + 1 < menus.Length)
{
Menu? menuToClose = menus[menu.Level + 1];
if (menuToClose != null && hideSubmenuDuringRefreshSearch)
{
HideOldMenu(menuToClose);
}
}
}
menu.UserDragsMenu += Menu_UserDragsMenu; menu.UserDragsMenu += Menu_UserDragsMenu;
void Menu_UserDragsMenu() void Menu_UserDragsMenu()
{ {
if (menus[1] != null) Menu? menu = menus[1];
if (menu != null)
{ {
HideOldMenu(menus[1]); HideOldMenu(menu);
} }
} }
@ -548,8 +588,7 @@ namespace SystemTrayMenu.Business
{ {
Log.Info("Ignored Deactivate, because openCloseState == OpenCloseState.Opening"); Log.Info("Ignored Deactivate, because openCloseState == OpenCloseState.Opening");
} }
else if (!Settings.Default.StaysOpenWhenFocusLostAfterEnterPressed || else if (!Settings.Default.StaysOpenWhenFocusLostAfterEnterPressed)
!waitingForReactivate)
{ {
FadeHalfOrOutIfNeeded(); FadeHalfOrOutIfNeeded();
if (!IsActive()) if (!IsActive())
@ -562,7 +601,7 @@ namespace SystemTrayMenu.Business
menu.Activated += (sender, e) => Activated(); menu.Activated += (sender, e) => Activated();
void Activated() void Activated()
{ {
if (IsActive() && menus[0].IsUsable) if (IsActive() && IsMainUsable)
{ {
AsList.ForEach(m => m.ShowWithFade()); AsList.ForEach(m => m.ShowWithFade());
timerStillActiveCheck.Stop(); timerStillActiveCheck.Stop();
@ -606,12 +645,11 @@ namespace SystemTrayMenu.Business
else else
{ {
// Sub Menu (loading) // Sub Menu (loading)
if (menus[0].IsUsable) if (IsMainUsable)
{ {
HideOldMenu(menu, true); HideOldMenu(menu, true);
menus[menu.Level] = menu; menus[menu.Level] = menu;
AdjustMenusSizeAndLocation(); menu.ShowWithFadeOrTransparent(IsActive());
menus[menu.Level]?.ShowWithFadeOrTransparent(IsActive());
} }
} }
@ -622,7 +660,7 @@ namespace SystemTrayMenu.Business
{ {
if (menu.IsUsable) if (menu.IsUsable)
{ {
AdjustMenusSizeAndLocation(); AdjustMenusSizeAndLocation(menu.Level);
if (menu.Level == 0) if (menu.Level == 0)
{ {
@ -725,13 +763,17 @@ namespace SystemTrayMenu.Business
private void Dgv_MouseUp(object sender, int index, MouseButtonEventArgs e) private void Dgv_MouseUp(object sender, int index, MouseButtonEventArgs e)
{ {
lastMouseDownRowIndex = -1; lastMouseDownRowIndex = -1;
#if TODO // TOUCH
isDraggingSwipeScrolling = false; isDraggingSwipeScrolling = false;
#endif
isDragSwipeScrolled = false; isDragSwipeScrolled = false;
} }
private void Dgv_MouseLeave(object sender, EventArgs e) private void Dgv_MouseLeave(object sender, EventArgs e)
{ {
#if TODO // TOUCH
isDraggingSwipeScrolling = false; isDraggingSwipeScrolling = false;
#endif
isDragSwipeScrolled = false; isDragSwipeScrolled = false;
} }
@ -742,7 +784,7 @@ namespace SystemTrayMenu.Business
private void MouseEnterOk(ListView dgv, int rowIndex, bool refreshView) private void MouseEnterOk(ListView dgv, int rowIndex, bool refreshView)
{ {
if (menus[0].IsUsable) if (IsMainUsable)
{ {
if (keyboardInput.InUse) if (keyboardInput.InUse)
{ {
@ -823,7 +865,7 @@ namespace SystemTrayMenu.Business
{ {
// Case when filtering a previous menu // Case when filtering a previous menu
} }
else if (!menus[0].IsUsable) else if (!IsMainUsable)
{ {
#if TODO // Colors #if TODO // Colors
row.DefaultCellStyle.SelectionBackColor = Color.White; row.DefaultCellStyle.SelectionBackColor = Color.White;
@ -900,7 +942,6 @@ namespace SystemTrayMenu.Business
if (rowData.ProcessStarted) if (rowData.ProcessStarted)
{ {
waitingForReactivate = true;
rowData.ProcessStarted = false; rowData.ProcessStarted = false;
row.Cells[0].Value = Resources.StaticResources.LoadingIcon; row.Cells[0].Value = Resources.StaticResources.LoadingIcon;
timerShowProcessStartedAsLoadingIcon.Tick += Tick; timerShowProcessStartedAsLoadingIcon.Tick += Tick;
@ -909,7 +950,6 @@ namespace SystemTrayMenu.Business
timerShowProcessStartedAsLoadingIcon.Tick -= Tick; timerShowProcessStartedAsLoadingIcon.Tick -= Tick;
timerShowProcessStartedAsLoadingIcon.Stop(); timerShowProcessStartedAsLoadingIcon.Stop();
row.Cells[0].Value = rowData.ReadIcon(false); row.Cells[0].Value = rowData.ReadIcon(false);
waitingForReactivate = false;
} }
timerShowProcessStartedAsLoadingIcon.Stop(); timerShowProcessStartedAsLoadingIcon.Stop();
@ -925,16 +965,21 @@ namespace SystemTrayMenu.Business
{ {
dispatchter.Invoke(() => dispatchter.Invoke(() =>
{ {
if (menus[0].IsUsable) if (IsMainUsable)
{ {
menus[0].RowDataParent = null; Menu? menu = menus[0];
if (menu != null)
{
// TODO: What does this do???
menu.RowDataParent = null;
}
} }
}); });
} }
private void HideOldMenu(Menu menuToShow, bool keepOrSetIsMenuOpen = false) private void HideOldMenu(Menu menuToShow, bool keepOrSetIsMenuOpen = false)
{ {
Menu menuPrevious = menus[menuToShow.Level - 1]; Menu? menuPrevious = menus[menuToShow.Level - 1];
if (menuPrevious != null) if (menuPrevious != null)
{ {
// Clean up menu status IsMenuOpen for previous one // Clean up menu status IsMenuOpen for previous one
@ -958,10 +1003,10 @@ namespace SystemTrayMenu.Business
} }
// Hide old menu // Hide old menu
foreach (Menu menuToClose in menus.Where( foreach (Menu? menuToClose in menus.Where(
m => m != null && m.Level > menuPrevious.Level)) m => m != null && m.Level > menuPrevious.Level))
{ {
menuToClose.HideWithFade(); menuToClose!.HideWithFade();
menus[menuToClose.Level] = null; menus[menuToClose.Level] = null;
} }
} }
@ -969,7 +1014,7 @@ namespace SystemTrayMenu.Business
private void FadeHalfOrOutIfNeeded() private void FadeHalfOrOutIfNeeded()
{ {
if (menus[0] != null && menus[0].IsUsable) if (IsMainUsable)
{ {
if (!IsActive()) if (!IsActive())
{ {
@ -1010,27 +1055,26 @@ namespace SystemTrayMenu.Business
joystickHelper.Disable(); joystickHelper.Disable();
} }
private void AdjustMenusSizeAndLocation() private void GetScreenBounds(out Rect screenBounds, out bool useCustomLocation, out Menu.StartLocation startLocation)
{ {
Rect screenBounds;
bool isCustomLocationOutsideOfScreen = false;
if (Settings.Default.AppearAtMouseLocation) if (Settings.Default.AppearAtMouseLocation)
{ {
screenBounds = NativeMethods.Screen.FromPoint(NativeMethods.Screen.CursorPosition); screenBounds = NativeMethods.Screen.FromPoint(NativeMethods.Screen.CursorPosition);
useCustomLocation = false;
} }
else if (Settings.Default.UseCustomLocation) else if (Settings.Default.UseCustomLocation)
{ {
screenBounds = NativeMethods.Screen.FromPoint(new ( screenBounds = NativeMethods.Screen.FromPoint(new(
Settings.Default.CustomLocationX, Settings.Default.CustomLocationX,
Settings.Default.CustomLocationY)); Settings.Default.CustomLocationY));
isCustomLocationOutsideOfScreen = !screenBounds.Contains( useCustomLocation = !screenBounds.Contains(
new Point(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY)); new Point(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY));
} }
else else
{ {
screenBounds = NativeMethods.Screen.PrimaryScreen; screenBounds = NativeMethods.Screen.PrimaryScreen;
useCustomLocation = false;
} }
// Only apply taskbar position change when no menu is currently open // Only apply taskbar position change when no menu is currently open
@ -1042,7 +1086,6 @@ namespace SystemTrayMenu.Business
} }
// Shrink the usable space depending on taskbar location // Shrink the usable space depending on taskbar location
Menu.StartLocation startLocation;
switch (taskbarPosition) switch (taskbarPosition)
{ {
case TaskbarPosition.Left: case TaskbarPosition.Left:
@ -1066,19 +1109,32 @@ namespace SystemTrayMenu.Business
break; break;
} }
if (Settings.Default.AppearAtTheBottomLeft || if (Settings.Default.AppearAtTheBottomLeft)
isCustomLocationOutsideOfScreen)
{ {
startLocation = Menu.StartLocation.BottomLeft; startLocation = Menu.StartLocation.BottomLeft;
} }
}
private void AdjustMenusSizeAndLocation(int startLevel)
{
GetScreenBounds(out Rect screenBounds, out bool useCustomLocation, out Menu.StartLocation startLocation);
Menu menu; Menu menu;
Menu? menuPredecessor = null; Menu? menuPredecessor = null;
List<Menu> list = AsList;
for (int i = 0; i < list.Count; i++) for (int i = 0; i < list.Count; i++)
{ {
menu = list[i]; menu = list[i];
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation, isCustomLocationOutsideOfScreen); if (startLevel <= i)
{
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation, useCustomLocation);
}
else
{
// Make sure further calculations of this menu access updated values (later used as predecessor)
menu.UpdateLayout();
}
if (!Settings.Default.AppearAtTheBottomLeft && if (!Settings.Default.AppearAtTheBottomLeft &&
!Settings.Default.AppearAtMouseLocation && !Settings.Default.AppearAtMouseLocation &&
@ -1110,31 +1166,6 @@ namespace SystemTrayMenu.Business
} }
#endif #endif
private void Menu_SearchTextChanging()
{
searchTextChanging = true;
keyboardInput.SearchTextChanging();
waitToOpenMenu.MouseActive = false;
}
private void Menu_SearchTextChanged(object sender, bool isSearchStringEmpty)
{
Menu menu = (Menu)sender;
keyboardInput.SearchTextChanged(menu, isSearchStringEmpty);
AdjustMenusSizeAndLocation();
searchTextChanging = false;
// if any open menu close
if (menu.Level + 1 < menus.Length)
{
Menu menuToClose = menus[menu.Level + 1];
if (menuToClose != null && hideSubmenuDuringRefreshSearch)
{
HideOldMenu(menuToClose);
}
}
}
private void ExecuteWatcherHistory() private void ExecuteWatcherHistory()
{ {
foreach (var fileSystemEventArgs in watcherHistory) foreach (var fileSystemEventArgs in watcherHistory)
@ -1147,14 +1178,15 @@ namespace SystemTrayMenu.Business
private void WatcherProcessItem(object sender, EventArgs e) private void WatcherProcessItem(object sender, EventArgs e)
{ {
Menu? menu = menus[0];
bool useHistory = false; bool useHistory = false;
if (menus[0] == null) if (menu == null)
{ {
useHistory = true; useHistory = true;
} }
else else
{ {
menus[0].Dispatcher.Invoke(() => useHistory = !menus[0].IsLoaded); menu.Dispatcher.Invoke(() => useHistory = !menu.IsLoaded);
} }
if (useHistory) if (useHistory)
@ -1165,17 +1197,17 @@ namespace SystemTrayMenu.Business
if (e is RenamedEventArgs renamedEventArgs) if (e is RenamedEventArgs renamedEventArgs)
{ {
menus[0].Dispatcher.Invoke(() => RenameItem(renamedEventArgs)); menus[0]?.Dispatcher.Invoke(() => RenameItem(renamedEventArgs));
} }
else if (e is FileSystemEventArgs fileSystemEventArgs) else if (e is FileSystemEventArgs fileSystemEventArgs)
{ {
if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Deleted) if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Deleted)
{ {
menus[0].Dispatcher.Invoke(() => DeleteItem(fileSystemEventArgs)); menus[0]?.Dispatcher.Invoke(() => DeleteItem(fileSystemEventArgs));
} }
else if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Created) else if (fileSystemEventArgs.ChangeType == WatcherChangeTypes.Created)
{ {
menus[0].Dispatcher.Invoke(() => CreateItem(fileSystemEventArgs)); menus[0]?.Dispatcher.Invoke(() => CreateItem(fileSystemEventArgs));
} }
} }
} }
@ -1185,23 +1217,27 @@ namespace SystemTrayMenu.Business
try try
{ {
List<RowData> rowDatas = new(); List<RowData> rowDatas = new();
ListView? dgv = menus[0].GetDataGridView(); ListView? dgv = menus[0]?.GetDataGridView();
if (dgv != null) if (dgv != null)
{ {
foreach (ListViewItemData item in dgv.Items) foreach (ListViewItemData item in dgv.Items)
{ {
RowData rowData = item.data; RowData rowData = item.data;
if (rowData.Path.StartsWith($"{e.OldFullPath}")) if (rowData.Path?.StartsWith($"{e.OldFullPath}") ?? false)
{ {
string path = rowData.Path.Replace(e.OldFullPath, e.FullPath); string? path = rowData.Path.Replace(e.OldFullPath, e.FullPath);
FileAttributes attr = File.GetAttributes(path); FileAttributes attr = File.GetAttributes(path);
bool isFolder = (attr & FileAttributes.Directory) == FileAttributes.Directory; bool isFolder = (attr & FileAttributes.Directory) == FileAttributes.Directory;
if (isFolder) if (isFolder)
{ {
path = Path.GetDirectoryName(path); path = Path.GetDirectoryName(path);
if (string.IsNullOrEmpty(path))
{
continue;
}
} }
RowData rowDataRenamed = new(isFolder, rowData.IsAddionalItem, false, 0, path); RowData rowDataRenamed = new(isFolder, rowData.IsAdditionalItem, false, 0, path);
if (FolderOptions.IsHidden(rowDataRenamed)) if (FolderOptions.IsHidden(rowDataRenamed))
{ {
continue; continue;
@ -1220,13 +1256,13 @@ namespace SystemTrayMenu.Business
rowDatas = DirectoryHelpers.SortItems(rowDatas); rowDatas = DirectoryHelpers.SortItems(rowDatas);
keyboardInput.ClearIsSelectedByKey(); keyboardInput.ClearIsSelectedByKey();
menus[0].AddItemsToMenu(rowDatas); menus[0]?.AddItemsToMenu(rowDatas);
hideSubmenuDuringRefreshSearch = false; hideSubmenuDuringRefreshSearch = false;
menus[0].RefreshSearchText(); menus[0]?.RefreshSearchText();
hideSubmenuDuringRefreshSearch = true; hideSubmenuDuringRefreshSearch = true;
menus[0].TimerUpdateIconsStart(); menus[0]?.TimerUpdateIconsStart();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -1238,7 +1274,7 @@ namespace SystemTrayMenu.Business
{ {
try try
{ {
ListView? dgv = menus[0].GetDataGridView(); ListView? dgv = menus[0]?.GetDataGridView();
if (dgv != null) if (dgv != null)
{ {
List<ListViewItemData> rowsToRemove = new(); List<ListViewItemData> rowsToRemove = new();
@ -1247,7 +1283,7 @@ namespace SystemTrayMenu.Business
{ {
RowData rowData = item.data; RowData rowData = item.data;
if (rowData.Path == e.FullPath || if (rowData.Path == e.FullPath ||
rowData.Path.StartsWith($"{e.FullPath}\\")) (rowData.Path?.StartsWith($"{e.FullPath}\\") ?? false))
{ {
IconReader.RemoveIconFromCache(rowData.Path); IconReader.RemoveIconFromCache(rowData.Path);
rowsToRemove.Add(item); rowsToRemove.Add(item);
@ -1263,7 +1299,7 @@ namespace SystemTrayMenu.Business
keyboardInput.ClearIsSelectedByKey(); keyboardInput.ClearIsSelectedByKey();
hideSubmenuDuringRefreshSearch = false; hideSubmenuDuringRefreshSearch = false;
menus[0].RefreshSearchText(); menus[0]?.RefreshSearchText();
hideSubmenuDuringRefreshSearch = true; hideSubmenuDuringRefreshSearch = true;
} }
catch (Exception ex) catch (Exception ex)
@ -1292,7 +1328,7 @@ namespace SystemTrayMenu.Business
rowData, rowData,
}; };
ListView? dgv = menus[0].GetDataGridView(); ListView? dgv = menus[0]?.GetDataGridView();
if (dgv != null) if (dgv != null)
{ {
foreach (ListViewItemData item in dgv.Items) foreach (ListViewItemData item in dgv.Items)
@ -1303,13 +1339,13 @@ namespace SystemTrayMenu.Business
rowDatas = DirectoryHelpers.SortItems(rowDatas); rowDatas = DirectoryHelpers.SortItems(rowDatas);
keyboardInput.ClearIsSelectedByKey(); keyboardInput.ClearIsSelectedByKey();
menus[0].AddItemsToMenu(rowDatas); menus[0]?.AddItemsToMenu(rowDatas);
hideSubmenuDuringRefreshSearch = false; hideSubmenuDuringRefreshSearch = false;
menus[0].RefreshSearchText(); menus[0]?.RefreshSearchText();
hideSubmenuDuringRefreshSearch = true; hideSubmenuDuringRefreshSearch = true;
menus[0].TimerUpdateIconsStart(); menus[0]?.TimerUpdateIconsStart();
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -31,14 +31,14 @@ namespace SystemTrayMenu.DataClasses
/// (Related replace "\x00" see #171.) /// (Related replace "\x00" see #171.)
/// </summary> /// </summary>
/// <param name="isFolder">Flag if file or folder.</param> /// <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="isAdditionalItem">Flag if additional item, from other folder than root folder.</param>
/// <param name="isNetworkRoot">Flag if resolved from network 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="level">The number of the menu level.</param>
/// <param name="path">Path to item.</param> /// <param name="path">Path to item.</param>
internal RowData(bool isFolder, bool isAddionalItem, bool isNetworkRoot, int level, string path) internal RowData(bool isFolder, bool isAdditionalItem, bool isNetworkRoot, int level, string path)
{ {
IsFolder = isFolder; IsFolder = isFolder;
IsAddionalItem = isAddionalItem; IsAdditionalItem = isAdditionalItem;
IsNetworkRoot = isNetworkRoot; IsNetworkRoot = isNetworkRoot;
Level = level; Level = level;
@ -106,7 +106,7 @@ namespace SystemTrayMenu.DataClasses
internal bool IsFolder { get; } internal bool IsFolder { get; }
internal bool IsAddionalItem { get; } internal bool IsAdditionalItem { get; }
internal bool IsNetworkRoot { get; } internal bool IsNetworkRoot { get; }
@ -182,6 +182,7 @@ namespace SystemTrayMenu.DataClasses
if (e != null && if (e != null &&
e.RightButton == MouseButtonState.Pressed && e.RightButton == MouseButtonState.Pressed &&
FileInfo != null && FileInfo != null &&
Path != null &&
dgv != null && dgv != null &&
dgv.Items.Count > RowIndex && dgv.Items.Count > RowIndex &&
(DateTime.Now - contextMenuClosed).TotalMilliseconds > 200) (DateTime.Now - contextMenuClosed).TotalMilliseconds > 200)
@ -235,7 +236,7 @@ namespace SystemTrayMenu.DataClasses
OpenItem(e, ref toCloseByDoubleClick); OpenItem(e, ref toCloseByDoubleClick);
} }
if (Properties.Settings.Default.OpenDirectoryWithOneClick && if (Properties.Settings.Default.OpenDirectoryWithOneClick && Path != null &&
ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed)) ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed))
{ {
Log.ProcessStart(Path); Log.ProcessStart(Path);
@ -255,7 +256,7 @@ namespace SystemTrayMenu.DataClasses
OpenItem(e, ref toCloseByDoubleClick); OpenItem(e, ref toCloseByDoubleClick);
} }
if (!Properties.Settings.Default.OpenDirectoryWithOneClick && if (!Properties.Settings.Default.OpenDirectoryWithOneClick && Path != null &&
ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed)) ContainsMenu && (e == null || e.LeftButton == MouseButtonState.Pressed))
{ {
Log.ProcessStart(Path); Log.ProcessStart(Path);
@ -268,7 +269,7 @@ namespace SystemTrayMenu.DataClasses
private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem) private void OpenItem(MouseEventArgs e, ref bool toCloseByOpenItem)
{ {
if (!ContainsMenu && if (!ContainsMenu && Path != null && ResolvedPath != null &&
(e == null || e.LeftButton == MouseButtonState.Pressed)) (e == null || e.LeftButton == MouseButtonState.Pressed))
{ {
ProcessStarted = true; ProcessStarted = true;

View file

@ -97,7 +97,7 @@
<DockPanel x:Name="searchPanel" DockPanel.Dock="Top" Margin="6,0"> <DockPanel x:Name="searchPanel" DockPanel.Dock="Top" Margin="6,0">
<Separator x:Name="panelLine" Height="1" Margin="0,1" DockPanel.Dock="Bottom"/> <Separator x:Name="panelLine" Height="1" Margin="0,1" DockPanel.Dock="Bottom"/>
<Image x:Name="pictureBoxSearch" Width="16" Height="16" Margin="1" DockPanel.Dock="Left" Source="{StaticResource ic_fluent_search_48_regularDrawingImage}"/> <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}" SelectionTextBrush="Red" SelectionBrush="#FFDAFF00" /> <TextBox x:Name="textBoxSearch" BorderBrush="{x:Null}" Background="{x:Null}" SelectionTextBrush="Red" SelectionBrush="#FFDAFF00" />
</DockPanel> </DockPanel>
<DockPanel x:Name="tableLayoutPanelBottom" DockPanel.Dock="Bottom" Margin="12,4"> <DockPanel x:Name="tableLayoutPanelBottom" DockPanel.Dock="Bottom" Margin="12,4">

View file

@ -296,9 +296,7 @@ namespace SystemTrayMenu.UserInterface
internal event Action? SearchTextChanging; internal event Action? SearchTextChanging;
#if TODO // SEARCH internal event Action<Menu, bool>? SearchTextChanged;
internal event EventHandler<bool> SearchTextChanged;
#endif
internal event Action? UserDragsMenu; internal event Action? UserDragsMenu;
@ -447,7 +445,7 @@ namespace SystemTrayMenu.UserInterface
foreach (RowData rowData in data) foreach (RowData rowData in data)
{ {
if (!(rowData.IsAddionalItem && Settings.Default.ShowOnlyAsSearchResult)) if (!(rowData.IsAdditionalItem && Settings.Default.ShowOnlyAsSearchResult))
{ {
if (rowData.ContainsMenu) if (rowData.ContainsMenu)
{ {
@ -464,7 +462,7 @@ namespace SystemTrayMenu.UserInterface
(rowData.HiddenEntry ? IconReader.AddIconOverlay(rowData.Icon, Properties.Resources.White50Percentage) : rowData.Icon)?.ToImageSource(), (rowData.HiddenEntry ? IconReader.AddIconOverlay(rowData.Icon, Properties.Resources.White50Percentage) : rowData.Icon)?.ToImageSource(),
rowData.Text ?? "?", rowData.Text ?? "?",
rowData, rowData,
rowData.IsAddionalItem && Settings.Default.ShowOnlyAsSearchResult ? 99 : 0)); rowData.IsAdditionalItem && Settings.Default.ShowOnlyAsSearchResult ? 99 : 0));
} }
dgv.ItemsSource = items; dgv.ItemsSource = items;
@ -550,26 +548,25 @@ namespace SystemTrayMenu.UserInterface
/// <param name="bounds">Screen coordinates where the menu is allowed to be drawn in.</param> /// <param name="bounds">Screen coordinates where the menu is allowed to be drawn in.</param>
/// <param name="menuPredecessor">Predecessor menu (when available).</param> /// <param name="menuPredecessor">Predecessor menu (when available).</param>
/// <param name="startLocation">Defines where the first menu is drawn (when no predecessor is set).</param> /// <param name="startLocation">Defines where the first menu is drawn (when no predecessor is set).</param>
/// <param name="isCustomLocationOutsideOfScreen">isCustomLocationOutsideOfScreen.</param> /// <param name="useCustomLocation">Use CustomLocation as start position.</param>
internal void AdjustSizeAndLocation( internal void AdjustSizeAndLocation(
Rect bounds, Rect bounds,
Menu? menuPredecessor, Menu? menuPredecessor,
StartLocation startLocation, StartLocation startLocation,
bool isCustomLocationOutsideOfScreen) bool useCustomLocation)
{ {
// Update the height and width // Update the height and width
AdjustDataGridViewHeight(menuPredecessor, bounds.Height); AdjustDataGridViewHeight(menuPredecessor, bounds.Height);
AdjustDataGridViewWidth(); AdjustDataGridViewWidth();
bool useCustomLocation = Settings.Default.UseCustomLocation || lastLocation.X > 0;
bool changeDirectionWhenOutOfBounds = true; bool changeDirectionWhenOutOfBounds = true;
if (menuPredecessor != null) if (Level > 0)
{ {
// Ignore start as we use predecessor // Sub Menu location depends on the location of its predecessor
startLocation = StartLocation.Predecessor; startLocation = StartLocation.Predecessor;
} }
else if (useCustomLocation && !isCustomLocationOutsideOfScreen) else if (useCustomLocation)
{ {
// Do not adjust location again because Cursor.Postion changed // Do not adjust location again because Cursor.Postion changed
if (RowDataParent != null) if (RowDataParent != null)
@ -607,17 +604,20 @@ namespace SystemTrayMenu.UserInterface
if (IsLoaded) if (IsLoaded)
{ {
AdjustSizeAndLocationInternal(); AdjustWindowPositionInternal();
} }
else else
{ {
// Layout cannot be calculated during loading, postpone this event // Layout cannot be calculated during loading, postpone this event
// TODO: Make sure lampa capture is registered only once // TODO: Make sure lampa capture is registered only once
Loaded += (_, _) => AdjustSizeAndLocationInternal(); Loaded += (_, _) => AdjustWindowPositionInternal();
} }
void AdjustSizeAndLocationInternal() void AdjustWindowPositionInternal()
{ {
// Make sure we have latest values of own window size
UpdateLayout();
// Calculate X position // Calculate X position
double x; double x;
switch (startLocation) switch (startLocation)
@ -715,12 +715,12 @@ namespace SystemTrayMenu.UserInterface
{ {
case StartLocation.Predecessor: case StartLocation.Predecessor:
RowData trigger = RowDataParent; RowData? trigger = RowDataParent;
ListView dgv = menuPredecessor!.GetDataGridView() !; ListView dgv = menuPredecessor!.GetDataGridView() !;
// Set position on same height as the selected row from predecessor // Set position on same height as the selected row from predecessor
y = menuPredecessor.Location.Y; y = menuPredecessor.Location.Y;
if (dgv.Items.Count > trigger.RowIndex) if (trigger != null && dgv.Items.Count > trigger.RowIndex)
{ {
// When item is not found, it might be invalidated due to resizing or moving // When item is not found, it might be invalidated due to resizing or moving
// After updating the layout the location should be available again. // After updating the layout the location should be available again.
@ -1071,9 +1071,9 @@ namespace SystemTrayMenu.UserInterface
} }
SetCounts(foldersCount, filesCount); SetCounts(foldersCount, filesCount);
#endif
SearchTextChanged.Invoke(this, string.IsNullOrEmpty(userPattern)); SearchTextChanged?.Invoke(this, string.IsNullOrEmpty(userPattern));
#if TODO // SEARCH
if (anyIconNotUpdated) if (anyIconNotUpdated)
{ {
timerUpdateIcons.Start(); timerUpdateIcons.Start();
@ -1258,7 +1258,7 @@ namespace SystemTrayMenu.UserInterface
/// </summary> /// </summary>
internal class ListViewItemData internal class ListViewItemData
{ {
public ListViewItemData(ImageSource columnIcon, string columnText, RowData rowData, int sortIndex) public ListViewItemData(ImageSource? columnIcon, string columnText, RowData rowData, int sortIndex)
{ {
ColumnIcon = columnIcon; ColumnIcon = columnIcon;
ColumnText = columnText; ColumnText = columnText;
@ -1266,7 +1266,7 @@ namespace SystemTrayMenu.UserInterface
SortIndex = sortIndex; SortIndex = sortIndex;
} }
public ImageSource ColumnIcon { get; set; } public ImageSource? ColumnIcon { get; set; }
public string ColumnText { get; set; } public string ColumnText { get; set; }
@ -1276,10 +1276,5 @@ namespace SystemTrayMenu.UserInterface
public int SortIndex { get; set; } public int SortIndex { get; set; }
} }
private void TextBoxSearch_TextInput(object sender, TextCompositionEventArgs e)
{
// TODO WPF
}
} }
} }