mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-07-03 13:31:02 +12:00
Refactor size and position logic
Fix issue that custom location was always detected being out of bounds
This commit is contained in:
parent
3464e3e4b9
commit
55c01e44b8
|
@ -60,88 +60,6 @@ namespace SystemTrayMenu.Business
|
|||
workerMainMenu.WorkerSupportsCancellation = true;
|
||||
workerMainMenu.DoWork += LoadMenu;
|
||||
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;
|
||||
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;
|
||||
int level = 0;
|
||||
BackgroundWorker? workerSelf = sender as BackgroundWorker;
|
||||
RowData? rowData = eDoWork.Argument as RowData;
|
||||
string? path;
|
||||
int level;
|
||||
if (rowData != null)
|
||||
{
|
||||
path = rowData.ResolvedPath;
|
||||
|
@ -464,13 +383,99 @@ namespace SystemTrayMenu.Business
|
|||
else
|
||||
{
|
||||
path = Config.Path;
|
||||
level = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
bool IsShellContextMenuOpen()
|
||||
|
@ -860,8 +865,7 @@ namespace SystemTrayMenu.Business
|
|||
Menu? menu = menus[0];
|
||||
if (menu != null)
|
||||
{
|
||||
// TODO: What does this do???
|
||||
menu.RowDataParent = null;
|
||||
menu.RelocateOnNextShow = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -958,7 +962,7 @@ namespace SystemTrayMenu.Business
|
|||
Settings.Default.CustomLocationX,
|
||||
Settings.Default.CustomLocationY));
|
||||
|
||||
useCustomLocation = !screenBounds.Contains(
|
||||
useCustomLocation = screenBounds.Contains(
|
||||
new Point(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY));
|
||||
}
|
||||
else
|
||||
|
|
|
@ -323,14 +323,17 @@ namespace SystemTrayMenu.UserInterface
|
|||
BottomLeft,
|
||||
BottomRight,
|
||||
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 RowData? RowDataParent { get; set; }
|
||||
|
||||
internal bool RelocateOnNextShow { get; set; } = true;
|
||||
|
||||
internal bool IsClosed { get; private set; } = false;
|
||||
|
||||
internal bool IsUsable => Visibility == Visibility.Visible && !isFading && !IsClosed;
|
||||
|
@ -542,86 +545,99 @@ namespace SystemTrayMenu.UserInterface
|
|||
StartLocation startLocation,
|
||||
bool useCustomLocation)
|
||||
{
|
||||
Point originLocation = new(0, 0);
|
||||
|
||||
// Update the height and width
|
||||
AdjustDataGridViewHeight(menuPredecessor, bounds.Height);
|
||||
AdjustDataGridViewWidth();
|
||||
|
||||
bool changeDirectionWhenOutOfBounds = true;
|
||||
|
||||
if (Level > 0)
|
||||
{
|
||||
if (menuPredecessor == null)
|
||||
{
|
||||
// should never happen
|
||||
return;
|
||||
}
|
||||
|
||||
// Sub Menu location depends on the location of its predecessor
|
||||
startLocation = StartLocation.Predecessor;
|
||||
originLocation = menuPredecessor.Location;
|
||||
}
|
||||
else if (useCustomLocation)
|
||||
{
|
||||
// Do not adjust location again because Cursor.Postion changed
|
||||
if (RowDataParent != null)
|
||||
if (!RelocateOnNextShow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Use this menu as predecessor and overwrite location with CustomLocation
|
||||
menuPredecessor = this;
|
||||
RowDataParent = new RowData();
|
||||
Left = Settings.Default.CustomLocationX;
|
||||
Top = Settings.Default.CustomLocationY;
|
||||
directionToRight = true;
|
||||
startLocation = StartLocation.Predecessor;
|
||||
changeDirectionWhenOutOfBounds = false;
|
||||
RelocateOnNextShow = false;
|
||||
originLocation = new(Settings.Default.CustomLocationX, Settings.Default.CustomLocationY);
|
||||
startLocation = StartLocation.Point;
|
||||
}
|
||||
else if (Settings.Default.AppearAtMouseLocation)
|
||||
{
|
||||
// Do not adjust location again because Cursor.Postion changed
|
||||
if (RowDataParent != null)
|
||||
if (!RelocateOnNextShow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Use this menu as predecessor and overwrite location with Cursor.Postion
|
||||
menuPredecessor = this;
|
||||
RowDataParent = new RowData();
|
||||
var position = Mouse.GetPosition(this);
|
||||
Left = position.X;
|
||||
Top = position.Y - labelTitle.Height;
|
||||
directionToRight = true;
|
||||
startLocation = StartLocation.Predecessor;
|
||||
changeDirectionWhenOutOfBounds = false;
|
||||
RelocateOnNextShow = false;
|
||||
originLocation = Mouse.GetPosition(this);
|
||||
originLocation.Y -= labelTitle.Height;
|
||||
startLocation = StartLocation.Point;
|
||||
}
|
||||
|
||||
if (IsLoaded)
|
||||
{
|
||||
AdjustWindowPositionInternal();
|
||||
AdjustWindowPositionInternal(originLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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
|
||||
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
|
||||
double x;
|
||||
switch (startLocation)
|
||||
{
|
||||
case StartLocation.Point:
|
||||
case StartLocation.Predecessor:
|
||||
double scaling = Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
|
||||
directionToRight = menuPredecessor!.directionToRight; // try keeping same direction
|
||||
|
||||
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)
|
||||
{
|
||||
x = menuPredecessor.Location.X - Width + scaling;
|
||||
x = originLocation.X - Width + scaling;
|
||||
if (x < bounds.X &&
|
||||
menuPredecessor.Location.X + menuPredecessor.Width < bounds.X + bounds.Width &&
|
||||
bounds.X + (bounds.Width / 2) > menuPredecessor.Location.X + (Width / 2))
|
||||
originLocation.X + menuPredecessor.Width < bounds.X + bounds.Width &&
|
||||
bounds.X + (bounds.Width / 2) > originLocation.X + (Width / 2))
|
||||
{
|
||||
x = bounds.X + bounds.Width - Width + scaling;
|
||||
}
|
||||
|
@ -638,15 +654,16 @@ namespace SystemTrayMenu.UserInterface
|
|||
}
|
||||
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 = menuPredecessor.Location.X + menuPredecessor.Width - scaling;
|
||||
x = originLocation.X + menuPredecessor.Width - scaling;
|
||||
if (x + Width > bounds.X + bounds.Width &&
|
||||
menuPredecessor.Location.X > bounds.X &&
|
||||
bounds.X + (bounds.Width / 2) < menuPredecessor.Location.X + (Width / 2))
|
||||
originLocation.X > bounds.X &&
|
||||
bounds.X + (bounds.Width / 2) < originLocation.X + (Width / 2))
|
||||
{
|
||||
x = bounds.X;
|
||||
}
|
||||
|
@ -699,13 +716,12 @@ namespace SystemTrayMenu.UserInterface
|
|||
double y;
|
||||
switch (startLocation)
|
||||
{
|
||||
case StartLocation.Point:
|
||||
case StartLocation.Predecessor:
|
||||
|
||||
RowData? trigger = RowDataParent;
|
||||
ListView dgv = menuPredecessor!.GetDataGridView()!;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// When item is not found, it might be invalidated due to resizing or moving
|
||||
|
|
Loading…
Reference in a new issue