Improve and fix location calculation of sub menus

This commit is contained in:
Peter Kirmeier 2022-12-02 19:34:24 +01:00
parent ada694c611
commit 6b1c63b2dc
2 changed files with 67 additions and 32 deletions

View file

@ -391,14 +391,12 @@ namespace SystemTrayMenu.UserInterface
buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed;
break; break;
case MenuType.Empty: case MenuType.Empty:
// TODO? remove search bar when searching makes no sense (take care of calculating initial position) searchPanel.Visibility = Visibility.Collapsed;
// searchPanel.Visibility = Visibility.Collapsed;
labelItems.Content = Translator.GetText("Directory empty"); labelItems.Content = Translator.GetText("Directory empty");
buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed;
break; break;
case MenuType.NoAccess: case MenuType.NoAccess:
// TODO? remove search bar when searching makes no sense (take care of calculating initial position) searchPanel.Visibility = Visibility.Collapsed;
// searchPanel.Visibility = Visibility.Collapsed;
labelItems.Content = Translator.GetText("Directory inaccessible"); labelItems.Content = Translator.GetText("Directory inaccessible");
buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed; buttonMenuAlwaysOpen.Visibility = Visibility.Collapsed;
break; break;
@ -716,40 +714,65 @@ namespace SystemTrayMenu.UserInterface
y = menuPredecessor.Location.Y; y = menuPredecessor.Location.Y;
if (dgv.Items.Count > trigger.RowIndex) if (dgv.Items.Count > trigger.RowIndex)
{ {
// TODO: Optimize calculation and fix calculation for items that are listed "beyond" the initial window size
// 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.
// It also makes sure all height and location information is up to date
menuPredecessor.UpdateLayout(); menuPredecessor.UpdateLayout();
ListViewItem? lvi = dgv.FindVisualChildOfType<ListViewItem>(trigger.RowIndex); #if TODO // SCROLL: bounds within list using scrollviewer index while calculating size once
if (lvi != null) // When scrolled, we have to reduce the index number as we calculate based on visual tree
int index = trigger.RowIndex;
ScrollViewer? scrollViewer = (VisualTreeHelper.GetChild(dgv, 0) as Decorator)?.Child as ScrollViewer;
if (scrollViewer != null)
{ {
double offset; // Show mid height or at bottom
if (scrollViewer.VerticalOffset <= index)
ScrollViewer? scrollViewer = (VisualTreeHelper.GetChild(dgv, 0) as Decorator)?.Child as ScrollViewer;
if (scrollViewer != null)
{ {
if (scrollViewer.VerticalOffset > 0) if ((int)(scrollViewer.VerticalOffset + scrollViewer.ViewportHeight) < index)
{ {
offset = 0D; // Outside of visible list while index is even further below: place at bottom (last entry)
for (int i = 0; i < scrollViewer.VerticalOffset; i++) index = (int)scrollViewer.ViewportHeight;
{ }
ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i); else
if (item != null) {
{ // Remove skipped entries from index when scrolled down
offset += item.ActualHeight; index -= (int)scrollViewer.VerticalOffset;
}
}
y -= (int)offset;
} }
} }
else
{
// Outside of visible list while index is even further above: place at top (first entry)
index = 0;
}
}
y += menuPredecessor.GetRelativeChildPositionTo(dgv).Y; y += menuPredecessor.GetRelativeChildPositionTo(dgv.FindVisualChildOfType<ListViewItem>(index)).Y;
#else // TODO: SCROLL: Sum up offsets by calculating final offset based on each items' height
// When scrolled, we have to reduce the index number as we calculate based on visual tree
int startIndex = 0;
double offset = 0D;
ScrollViewer? scrollViewer = (VisualTreeHelper.GetChild(dgv, 0) as Decorator)?.Child as ScrollViewer;
if (scrollViewer != null)
{
startIndex = (int)scrollViewer.VerticalOffset;
if (trigger.RowIndex < startIndex)
{
// calculate position above starting point
for (int i = trigger.RowIndex; i < startIndex; i++)
{
ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i);
if (item != null)
{
offset -= item.ActualHeight;
}
}
}
}
offset = 0D; if (startIndex < trigger.RowIndex)
for (int i = 0; i < trigger.RowIndex; i++) {
// calculate position below starting point
for (int i = startIndex; i < trigger.RowIndex; i++)
{ {
ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i); ListViewItem? item = dgv.FindVisualChildOfType<ListViewItem>(i);
if (item != null) if (item != null)
@ -757,22 +780,34 @@ namespace SystemTrayMenu.UserInterface
offset += item.ActualHeight; offset += item.ActualHeight;
} }
} }
y += (int)offset;
} }
y += menuPredecessor.GetRelativeChildPositionTo(dgv).Y + (int)offset;
#endif
} }
#if TODO // SCROLL: Do we want this - Move upwards when there is no content? (Feels odd to me, topeterk)
// Maybe always move it up only the height of labelTitle?
// when warning is shown, the title should appear at same height as selected row // when warning is shown, the title should appear at same height as selected row
if (searchPanel.Visibility != Visibility.Visible) if (searchPanel.Visibility != Visibility.Visible)
{ {
y += labelTitle.ActualHeight; // TODO: This seems to fail in version 1 as search bar is always visible, so no adjustement is made
// And even when adjustment is made, it moves the menu even further down rather up?
y -= this.GetRelativeChildPositionTo(labelItems).Y;
} }
#endif
// Move vertically when out of bounds // Move vertically when out of bounds
if (bounds.Y + bounds.Height < y + Height) if (bounds.Y + bounds.Height < y + Height)
{ {
y = bounds.Y + bounds.Height - Height; y = bounds.Y + bounds.Height - Height;
} }
#if !TODO // SCROLL: Upper screen bounds
else if (y < bounds.Y)
{
y = bounds.Y;
}
#endif
break; break;
case StartLocation.TopRight: case StartLocation.TopRight:

View file

@ -81,9 +81,9 @@ namespace SystemTrayMenu.Utilities
return null; return null;
} }
internal static Point GetRelativeChildPositionTo(this Visual parent, Visual child) internal static Point GetRelativeChildPositionTo(this Visual parent, Visual? child)
{ {
return child.TransformToAncestor(parent).Transform(new(0, 0)); return child == null ? new() : child.TransformToAncestor(parent).Transform(new ());
} }
// TODO: Find and remove any unnecessary convertions // TODO: Find and remove any unnecessary convertions