Refactor size and position logic

Fix issue that custom location was always detected being out of bounds
This commit is contained in:
Peter Kirmeier 2023-04-22 21:04:34 +02:00
parent 3464e3e4b9
commit 55c01e44b8
2 changed files with 150 additions and 130 deletions

View file

@ -60,88 +60,6 @@ namespace SystemTrayMenu.Business
workerMainMenu.WorkerSupportsCancellation = true; workerMainMenu.WorkerSupportsCancellation = true;
workerMainMenu.DoWork += LoadMenu; workerMainMenu.DoWork += LoadMenu;
workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted; workerMainMenu.RunWorkerCompleted += LoadMainMenuCompleted;
void LoadMainMenuCompleted(object? sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped?.Invoke();
if (e.Result == null)
{
// The main menu gets loaded again
// Clean up menu status of previous one
ListView? dgvMainMenu = menus[0]?.GetDataGridView();
if (dgvMainMenu != null)
{
foreach (ListViewItemData item in dgvMainMenu.Items)
{
RowData rowDataToClear = item.data;
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsClicking = false;
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
RefreshSelection(dgvMainMenu);
}
if (Settings.Default.AppearAtMouseLocation)
{
Menu? menu = menus[0];
if (menu != null)
{
menu.RowDataParent = null;
}
}
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
else
{
// First time the main menu gets loaded
MenuData menuData = (MenuData)e.Result;
switch (menuData.DirectoryState)
{
case MenuDataDirectoryState.Valid:
if (IconReader.IsPreloading)
{
workerMainMenu.DoWork -= LoadMenu;
workerMainMenu.CancelAsync();
Create(menuData, Config.Path); // Level 0 Main Menu
IconReader.IsPreloading = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
break;
case MenuDataDirectoryState.Empty:
MessageBox.Show(Translator.GetText("Your root directory for the app does not exist or is empty! Change the root directory or put some files, directories or shortcuts into the root directory."));
OpenFolder();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataDirectoryState.NoAccess:
MessageBox.Show(Translator.GetText("You have no access to the root directory of the app. Grant access to the directory or change the root directory."));
OpenFolder();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataDirectoryState.Undefined:
Log.Info($"{nameof(MenuDataDirectoryState)}.{nameof(MenuDataDirectoryState.Undefined)}");
break;
default:
break;
}
}
openCloseState = OpenCloseState.Default;
}
waitToOpenMenu.StopLoadMenu += WaitToOpenMenu_StopLoadMenu; waitToOpenMenu.StopLoadMenu += WaitToOpenMenu_StopLoadMenu;
void WaitToOpenMenu_StopLoadMenu() void WaitToOpenMenu_StopLoadMenu()
@ -446,11 +364,12 @@ namespace SystemTrayMenu.Business
} }
} }
private static void LoadMenu(object? senderDoWork, DoWorkEventArgs eDoWork) private static void LoadMenu(object? sender, DoWorkEventArgs eDoWork)
{ {
string? path; BackgroundWorker? workerSelf = sender as BackgroundWorker;
int level = 0;
RowData? rowData = eDoWork.Argument as RowData; RowData? rowData = eDoWork.Argument as RowData;
string? path;
int level;
if (rowData != null) if (rowData != null)
{ {
path = rowData.ResolvedPath; path = rowData.ResolvedPath;
@ -464,13 +383,99 @@ namespace SystemTrayMenu.Business
else else
{ {
path = Config.Path; path = Config.Path;
level = 0;
} }
MenuData menuData = new(level, rowData); MenuData menuData = new(level, rowData);
DirectoryHelpers.DiscoverItems((BackgroundWorker?)senderDoWork, path, ref menuData); DirectoryHelpers.DiscoverItems(workerSelf, path, ref menuData);
if (menuData.DirectoryState != MenuDataDirectoryState.Undefined &&
workerSelf != null && level == 0)
{
// After success of MainMenu loading: never run again
workerSelf.DoWork -= LoadMenu;
}
eDoWork.Result = menuData; eDoWork.Result = menuData;
} }
private void LoadMainMenuCompleted(object? sender, RunWorkerCompletedEventArgs e)
{
keyboardInput.ResetSelectedByKey();
LoadStopped?.Invoke();
if (e.Result == null)
{
Menu? menu = menus[0];
if (menu != null)
{
// The main menu gets loaded again
// Clean up menu status of previous one
ListView? dgvMainMenu = menu.GetDataGridView();
if (dgvMainMenu != null)
{
foreach (ListViewItemData item in dgvMainMenu.Items)
{
RowData rowDataToClear = item.data;
rowDataToClear.IsMenuOpen = false;
rowDataToClear.IsClicking = false;
rowDataToClear.IsSelected = false;
rowDataToClear.IsContextMenuOpen = false;
}
RefreshSelection(dgvMainMenu);
}
menu.RelocateOnNextShow = true;
}
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
else
{
// First time the main menu gets loaded
MenuData menuData = (MenuData)e.Result;
switch (menuData.DirectoryState)
{
case MenuDataDirectoryState.Valid:
if (IconReader.IsPreloading)
{
Create(menuData, Config.Path); // Level 0 Main Menu
IconReader.IsPreloading = false;
if (showMenuAfterMainPreload)
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
}
else
{
AsEnumerable.ToList().ForEach(m => { m.ShowWithFade(); });
}
break;
case MenuDataDirectoryState.Empty:
MessageBox.Show(Translator.GetText("Your root directory for the app does not exist or is empty! Change the root directory or put some files, directories or shortcuts into the root directory."));
OpenFolder();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataDirectoryState.NoAccess:
MessageBox.Show(Translator.GetText("You have no access to the root directory of the app. Grant access to the directory or change the root directory."));
OpenFolder();
Config.SetFolderByUser();
AppRestart.ByConfigChange();
break;
case MenuDataDirectoryState.Undefined:
Log.Info($"{nameof(MenuDataDirectoryState)}.{nameof(MenuDataDirectoryState.Undefined)}");
break;
default:
break;
}
}
openCloseState = OpenCloseState.Default;
}
private bool IsActive() private bool IsActive()
{ {
bool IsShellContextMenuOpen() bool IsShellContextMenuOpen()
@ -860,8 +865,7 @@ namespace SystemTrayMenu.Business
Menu? menu = menus[0]; Menu? menu = menus[0];
if (menu != null) if (menu != null)
{ {
// TODO: What does this do??? menu.RelocateOnNextShow = true;
menu.RowDataParent = null;
} }
} }
}); });
@ -958,7 +962,7 @@ namespace SystemTrayMenu.Business
Settings.Default.CustomLocationX, Settings.Default.CustomLocationX,
Settings.Default.CustomLocationY)); Settings.Default.CustomLocationY));
useCustomLocation = !screenBounds.Contains( useCustomLocation = screenBounds.Contains(
new Point(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY)); new Point(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY));
} }
else else

View file

@ -323,14 +323,17 @@ namespace SystemTrayMenu.UserInterface
BottomLeft, BottomLeft,
BottomRight, BottomRight,
TopRight, TopRight,
Point,
} }
public System.Drawing.Point Location => new ((int)Left, (int)Top); // TODO WPF Replace Forms wrapper public Point Location => new (Left, Top); // TODO WPF Replace Forms wrapper
internal int Level { get; set; } internal int Level { get; set; }
internal RowData? RowDataParent { get; set; } internal RowData? RowDataParent { get; set; }
internal bool RelocateOnNextShow { get; set; } = true;
internal bool IsClosed { get; private set; } = false; internal bool IsClosed { get; private set; } = false;
internal bool IsUsable => Visibility == Visibility.Visible && !isFading && !IsClosed; internal bool IsUsable => Visibility == Visibility.Visible && !isFading && !IsClosed;
@ -542,86 +545,99 @@ namespace SystemTrayMenu.UserInterface
StartLocation startLocation, StartLocation startLocation,
bool useCustomLocation) bool useCustomLocation)
{ {
Point originLocation = new(0, 0);
// Update the height and width // Update the height and width
AdjustDataGridViewHeight(menuPredecessor, bounds.Height); AdjustDataGridViewHeight(menuPredecessor, bounds.Height);
AdjustDataGridViewWidth(); AdjustDataGridViewWidth();
bool changeDirectionWhenOutOfBounds = true;
if (Level > 0) if (Level > 0)
{ {
if (menuPredecessor == null)
{
// should never happen
return;
}
// Sub Menu location depends on the location of its predecessor // Sub Menu location depends on the location of its predecessor
startLocation = StartLocation.Predecessor; startLocation = StartLocation.Predecessor;
originLocation = menuPredecessor.Location;
} }
else if (useCustomLocation) else if (useCustomLocation)
{ {
// Do not adjust location again because Cursor.Postion changed if (!RelocateOnNextShow)
if (RowDataParent != null)
{ {
return; return;
} }
// Use this menu as predecessor and overwrite location with CustomLocation RelocateOnNextShow = false;
menuPredecessor = this; originLocation = new(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY);
RowDataParent = new RowData(); startLocation = StartLocation.Point;
Left = Settings.Default.CustomLocationX;
Top = Settings.Default.CustomLocationY;
directionToRight = true;
startLocation = StartLocation.Predecessor;
changeDirectionWhenOutOfBounds = false;
} }
else if (Settings.Default.AppearAtMouseLocation) else if (Settings.Default.AppearAtMouseLocation)
{ {
// Do not adjust location again because Cursor.Postion changed if (!RelocateOnNextShow)
if (RowDataParent != null)
{ {
return; return;
} }
// Use this menu as predecessor and overwrite location with Cursor.Postion RelocateOnNextShow = false;
menuPredecessor = this; originLocation = Mouse.GetPosition(this);
RowDataParent = new RowData(); originLocation.Y -= labelTitle.Height;
var position = Mouse.GetPosition(this); startLocation = StartLocation.Point;
Left = position.X;
Top = position.Y - labelTitle.Height;
directionToRight = true;
startLocation = StartLocation.Predecessor;
changeDirectionWhenOutOfBounds = false;
} }
if (IsLoaded) if (IsLoaded)
{ {
AdjustWindowPositionInternal(); AdjustWindowPositionInternal(originLocation);
} }
else else
{ {
// Layout cannot be calculated during loading, postpone this event // Layout cannot be calculated during loading, postpone this event
Loaded += (_, _) => AdjustWindowPositionInternal(); Loaded += (_, _) => AdjustWindowPositionInternal(originLocation);
} }
void AdjustWindowPositionInternal() void AdjustWindowPositionInternal(Point originLocation)
{ {
RowData? trigger;
// Make sure we have latest values of own window size // Make sure we have latest values of own window size
UpdateLayout(); UpdateLayout();
// Prepare parameters
if (startLocation == StartLocation.Predecessor && menuPredecessor != null)
{
directionToRight = menuPredecessor.directionToRight; // try keeping same direction from predecessor
trigger = RowDataParent;
}
else
{
// Use own menu as predecessor for calculations (Left and Top were set beforehand)
menuPredecessor = this;
directionToRight = true; // use right as default direction
trigger = new();
}
// Calculate X position // Calculate X position
double x; double x;
switch (startLocation) switch (startLocation)
{ {
case StartLocation.Point:
case StartLocation.Predecessor: case StartLocation.Predecessor:
double scaling = Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero); double scaling = Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
directionToRight = menuPredecessor!.directionToRight; // try keeping same direction
if (directionToRight) if (directionToRight)
{ {
x = menuPredecessor.Location.X + menuPredecessor.Width - scaling; x = originLocation.X + menuPredecessor.Width - scaling;
if (changeDirectionWhenOutOfBounds && // Change direction when out of bounds (predecessor only)
if (startLocation == StartLocation.Predecessor &&
bounds.X + bounds.Width <= x + Width - scaling) bounds.X + bounds.Width <= x + Width - scaling)
{ {
x = menuPredecessor.Location.X - Width + scaling; x = originLocation.X - Width + scaling;
if (x < bounds.X && if (x < bounds.X &&
menuPredecessor.Location.X + menuPredecessor.Width < bounds.X + bounds.Width && originLocation.X + menuPredecessor.Width < bounds.X + bounds.Width &&
bounds.X + (bounds.Width / 2) > menuPredecessor.Location.X + (Width / 2)) bounds.X + (bounds.Width / 2) > originLocation.X + (Width / 2))
{ {
x = bounds.X + bounds.Width - Width + scaling; x = bounds.X + bounds.Width - Width + scaling;
} }
@ -638,15 +654,16 @@ namespace SystemTrayMenu.UserInterface
} }
else else
{ {
x = menuPredecessor.Location.X - Width + scaling; x = originLocation.X - Width + scaling;
if (changeDirectionWhenOutOfBounds && // Change direction when out of bounds (predecessor only)
if (startLocation == StartLocation.Predecessor &&
x < bounds.X) x < bounds.X)
{ {
x = menuPredecessor.Location.X + menuPredecessor.Width - scaling; x = originLocation.X + menuPredecessor.Width - scaling;
if (x + Width > bounds.X + bounds.Width && if (x + Width > bounds.X + bounds.Width &&
menuPredecessor.Location.X > bounds.X && originLocation.X > bounds.X &&
bounds.X + (bounds.Width / 2) < menuPredecessor.Location.X + (Width / 2)) bounds.X + (bounds.Width / 2) < originLocation.X + (Width / 2))
{ {
x = bounds.X; x = bounds.X;
} }
@ -699,13 +716,12 @@ namespace SystemTrayMenu.UserInterface
double y; double y;
switch (startLocation) switch (startLocation)
{ {
case StartLocation.Point:
case StartLocation.Predecessor: case StartLocation.Predecessor:
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 = originLocation.Y;
if (trigger != null && 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