Merge pull request #136 from Hofknecht/feature/taskbar_orientation

Feature/taskbar orientation
This commit is contained in:
Markus Hofknecht 2020-09-25 19:18:36 +02:00 committed by GitHub
commit cbdef123ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 224 additions and 156 deletions

View file

@ -27,11 +27,6 @@ namespace SystemTrayMenu.Business
private readonly BackgroundWorker workerMainMenu = new BackgroundWorker();
private readonly List<BackgroundWorker> workersSubMenu = new List<BackgroundWorker>();
private readonly int screenHeight = Screen.PrimaryScreen.Bounds.Height;
private readonly int screenWidth = Screen.PrimaryScreen.Bounds.Width;
private readonly int screenRight = Screen.PrimaryScreen.Bounds.Right;
private readonly int taskbarHeight = new WindowsTaskbar().Size.Height;
private readonly DgvMouseRow dgvMouseRow = new DgvMouseRow();
private readonly WaitToLoadMenu waitToOpenMenu = new WaitToLoadMenu();
private readonly KeyboardInput keyboardInput = null;
@ -41,6 +36,7 @@ namespace SystemTrayMenu.Business
private OpenCloseState openCloseState = OpenCloseState.Default;
private RowData loadingRowData = null;
private bool showingMessageBox = false;
private TaskbarPosition taskbarPosition = new WindowsTaskbar().Position;
public Menus()
{
@ -513,7 +509,7 @@ namespace SystemTrayMenu.Business
menus[0] = Create(
GetData(workerMainMenu, Config.Path, 0),
Path.GetFileName(Config.Path));
menus[0].AdjustSizeAndLocation(screenHeight, screenRight, taskbarHeight);
AdjustMenusSizeAndLocation();
DisposeMenu(menus[0]);
}
@ -859,34 +855,66 @@ namespace SystemTrayMenu.Business
private void AdjustMenusSizeAndLocation()
{
Menu menuPredecessor = menus[0];
int widthPredecessors = -1; // -1 padding
bool directionToRight = false;
WindowsTaskbar taskbar = new WindowsTaskbar();
Menu menuPredecessor = null;
List<Menu> list = AsList;
Menu menu;
Rectangle screenBounds = Screen.PrimaryScreen.Bounds;
Menu.StartLocation startLocation;
menus[0].AdjustSizeAndLocation(screenHeight, screenRight, taskbarHeight);
// Only apply taskbar position change when no menu is currently open
if (list.Count == 1)
{
taskbarPosition = taskbar.Position;
}
foreach (Menu menu in AsEnumerable.Where(m => m.Level > 0))
// Shrink the usable space depending on taskbar location
switch (taskbarPosition)
{
case TaskbarPosition.Left:
screenBounds.X += taskbar.Size.Width;
screenBounds.Width -= taskbar.Size.Width;
startLocation = Menu.StartLocation.BottomLeft;
break;
case TaskbarPosition.Right:
screenBounds.Width -= taskbar.Size.Width;
startLocation = Menu.StartLocation.BottomRight;
break;
case TaskbarPosition.Top:
screenBounds.Y += taskbar.Size.Height;
screenBounds.Height -= taskbar.Size.Height;
startLocation = Menu.StartLocation.TopRight;
break;
case TaskbarPosition.Bottom:
default:
screenBounds.Height -= taskbar.Size.Height;
startLocation = Menu.StartLocation.BottomRight;
break;
}
for (int i = 0; i < list.Count; i++)
{
int newWith = menu.Width - menu.Padding.Horizontal + menuPredecessor.Width;
if (directionToRight)
menu = list[i];
// Only last one has to be updated as all previous one were already updated in the past
if (list.Count - 1 == i)
{
if (widthPredecessors - menus[0].Width - menu.Width < 0)
{
directionToRight = false;
}
else
{
widthPredecessors -= newWith;
}
}
else if (screenWidth < widthPredecessors + menus[0].Width + menu.Width)
{
directionToRight = true;
widthPredecessors -= newWith;
menu.AdjustSizeAndLocation(screenBounds, menuPredecessor, startLocation);
}
if (i == 0)
{
const int overlapTolerance = 4;
// Remember width of the initial menu as we don't want to overlap with it
if (taskbarPosition == TaskbarPosition.Left)
{
screenBounds.X += menu.Width - overlapTolerance;
}
screenBounds.Width -= menu.Width - overlapTolerance;
}
menu.AdjustSizeAndLocation(screenHeight, screenRight, taskbarHeight, menuPredecessor, directionToRight);
widthPredecessors += menu.Width - menu.Padding.Left;
menuPredecessor = menu;
}
}

View file

@ -39,5 +39,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.15.1")]
[assembly: AssemblyFileVersion("1.0.15.1")]
[assembly: AssemblyVersion("1.0.16.0")]
[assembly: AssemblyFileVersion("1.0.16.0")]

View file

@ -154,6 +154,24 @@ namespace SystemTrayMenu.Properties
SaveValuesToFile();
}
/// <summary>
/// Creates an empty user.config file...looks like the one MS creates.
/// This could be overkill a simple key/value pairing would probably do.
/// </summary>
private static void CreateEmptyConfig()
{
var doc = new XDocument();
var declaration = new XDeclaration("1.0", "utf-8", "true");
var config = new XElement(Config);
var userSettings = new XElement(UserSettings);
var group = new XElement(typeof(Properties.Settings).FullName);
userSettings.Add(group);
config.Add(userSettings);
doc.Add(config);
doc.Declaration = declaration;
doc.Save(UserConfigPath);
}
/// <summary>
/// Loads the values of the file into memory.
/// </summary>
@ -185,24 +203,6 @@ namespace SystemTrayMenu.Properties
}
}
/// <summary>
/// Creates an empty user.config file...looks like the one MS creates.
/// This could be overkill a simple key/value pairing would probably do.
/// </summary>
private void CreateEmptyConfig()
{
var doc = new XDocument();
var declaration = new XDeclaration("1.0", "utf-8", "true");
var config = new XElement(Config);
var userSettings = new XElement(UserSettings);
var group = new XElement(typeof(Properties.Settings).FullName);
userSettings.Add(group);
config.Add(userSettings);
doc.Add(config);
doc.Declaration = declaration;
doc.Save(UserConfigPath);
}
/// <summary>
/// Saves the in memory dictionary to the user config file.
/// </summary>

View file

@ -94,14 +94,14 @@ namespace SystemTrayMenu.Helper
AppMoreInfo = versionInfo.LegalCopyright,
};
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "Markus Hofknecht (mailto:Markus@Hofknecht.eu)";
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "Tanja Kauth (mailto:Tanja@Hofknecht.eu)";
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "http://www.hofknecht.eu/systemtraymenu/";
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "https://github.com/Hofknecht/SystemTrayMenu";
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "Markus Hofknecht (mailto:Markus@Hofknecht.eu)" + Environment.NewLine;
ab.AppMoreInfo += "Tanja Kauth (mailto:Tanja@Hofknecht.eu)" + Environment.NewLine;
// Thanks for letting me being part of this project and that I am allowed to be listed here :-)
ab.AppMoreInfo += "Peter Kirmeier (mai" + "lto:top" + "ete" + "rk@f" + "reen" + "et." + "de)" + Environment.NewLine;
ab.AppMoreInfo += "http://www.hofknecht.eu/systemtraymenu/" + Environment.NewLine;
ab.AppMoreInfo += "https://github.com/Hofknecht/SystemTrayMenu" + Environment.NewLine;
ab.AppMoreInfo += Environment.NewLine;
ab.AppMoreInfo += "GNU GENERAL PUBLIC LICENSE" + Environment.NewLine;
ab.AppMoreInfo += "(Version 3, 29 June 2007)" + Environment.NewLine;

View file

@ -20,6 +20,7 @@ namespace SystemTrayMenu.UserInterface
{
private readonly Fading fading = new Fading();
private bool isShowing = false;
private bool directionToRight = false;
internal Menu()
{
@ -149,6 +150,14 @@ namespace SystemTrayMenu.UserInterface
MaxReached,
}
internal enum StartLocation
{
Predecessor,
BottomLeft,
BottomRight,
TopRight,
}
internal int Level { get; set; } = 0;
internal bool IsUsable => Visible && !fading.IsHiding &&
@ -278,122 +287,107 @@ namespace SystemTrayMenu.UserInterface
}
}
/// <summary>
/// Update the position and size of the menu.
/// </summary>
/// <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="startLocation">Defines where the first menu is drawn (when no predecessor is set).</param>
internal void AdjustSizeAndLocation(
int screenHeight,
int screenRight,
int taskbarHeight,
Menu menuPredecessor = null,
bool directionToRight = false)
Rectangle bounds,
Menu menuPredecessor,
StartLocation startLocation)
{
CheckForAutoResizeRowDone();
void CheckForAutoResizeRowDone()
if (menuPredecessor != null)
{
double factor = 1;
if (NativeMethods.IsTouchEnabled())
{
factor = 1.5;
}
if (menuPredecessor == null)
{
if (dgv.Tag == null && dgv.Rows.Count > 0)
{
dgv.AutoResizeRows();
dgv.RowTemplate.Height = (int)(dgv.Rows[0].Height * factor);
foreach (DataGridViewRow row in dgv.Rows)
{
row.Height = dgv.RowTemplate.Height;
}
dgv.Tag = true;
}
}
else
{
dgv.RowTemplate.Height = menuPredecessor.GetDataGridView().
RowTemplate.Height;
foreach (DataGridViewRow row in dgv.Rows)
{
row.Height = dgv.RowTemplate.Height;
}
dgv.Tag = true;
}
}
int dgvHeightNeeded = dgv.Rows.GetRowsHeight(
DataGridViewElementStates.None);
int menuRestNeeded = Height - dgv.Height;
int dgvHeightMax = screenHeight - taskbarHeight -
menuRestNeeded;
if (dgvHeightNeeded > dgvHeightMax)
{
dgvHeightNeeded = dgvHeightMax;
}
DataTable data = (DataTable)dgv.DataSource;
if (string.IsNullOrEmpty(data.DefaultView.RowFilter))
{
dgv.Height = dgvHeightNeeded;
// Ignore start as we use predecessor
startLocation = StartLocation.Predecessor;
}
// Update the height and width
AdjustDataGridViewHeight(menuPredecessor, bounds.Height);
AdjustDataGridViewWidth();
// Calculate X position
int x;
if (menuPredecessor == null)
switch (startLocation)
{
x = screenRight - Width;
}
else
{
if (directionToRight)
{
x = menuPredecessor.Location.X +
menuPredecessor.Width -
(int)Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
}
else
{
x = menuPredecessor.Location.X -
Width +
(int)Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
}
}
if (x < 0)
{
x += menuPredecessor.Width;
x += Width;
case StartLocation.Predecessor:
int scaling = (int)Math.Round(Scaling.Factor, 0, MidpointRounding.AwayFromZero);
directionToRight = menuPredecessor.directionToRight; // try keeping same direction
if (directionToRight)
{
x = menuPredecessor.Location.X + menuPredecessor.Width - scaling;
// Change direction when out of bounds
if (bounds.X + bounds.Width <= x + Width - scaling)
{
x = menuPredecessor.Location.X - Width + scaling;
directionToRight = !directionToRight;
}
}
else
{
x = menuPredecessor.Location.X - Width + scaling;
// Change direction when out of bounds
if (x < bounds.X)
{
x = menuPredecessor.Location.X + menuPredecessor.Width - scaling;
directionToRight = !directionToRight;
}
}
break;
case StartLocation.BottomLeft:
x = bounds.X;
directionToRight = true;
break;
case StartLocation.TopRight:
case StartLocation.BottomRight:
default:
x = bounds.Width - Width;
directionToRight = false;
break;
}
// Calculate Y position
int y;
if (menuPredecessor == null)
switch (startLocation)
{
y = screenHeight - taskbarHeight - Height;
}
else
{
RowData trigger = (RowData)Tag;
DataGridView dgv = menuPredecessor.GetDataGridView();
int distanceFromItemToDgvTop = 0;
if (dgv.Rows.Count > trigger.RowIndex)
{
Rectangle cellRectangle = dgv.GetCellDisplayRectangle(
0, trigger.RowIndex, false);
distanceFromItemToDgvTop = cellRectangle.Top;
}
case StartLocation.Predecessor:
RowData trigger = (RowData)Tag;
DataGridView dgv = menuPredecessor.GetDataGridView();
int distanceFromItemToDgvTop = 0;
y = menuPredecessor.Location.Y +
menuPredecessor.dgv.Location.Y +
distanceFromItemToDgvTop;
if ((y + Height - tableLayoutPanelSearch.Height) > dgvHeightMax)
{
y = dgvHeightMax - Height + menuRestNeeded;
}
// Get offset of selected row from predecessor
if (dgv.Rows.Count > trigger.RowIndex)
{
Rectangle cellRectangle = dgv.GetCellDisplayRectangle(0, trigger.RowIndex, false);
distanceFromItemToDgvTop = cellRectangle.Top;
}
// Set position on same height as the selected row from predecessor
y = menuPredecessor.Location.Y + menuPredecessor.dgv.Location.Y + distanceFromItemToDgvTop;
// Move vertically when out of bounds
if (bounds.Height < y + Height)
{
y = bounds.Y + bounds.Height - Height;
}
break;
case StartLocation.TopRight:
y = bounds.Y;
break;
case StartLocation.BottomLeft:
case StartLocation.BottomRight:
default:
y = bounds.Height - Height;
break;
}
// Update position
Location = new Point(x, y);
}
@ -439,6 +433,52 @@ namespace SystemTrayMenu.UserInterface
CultureInfo.InvariantCulture);
}
private void AdjustDataGridViewHeight(Menu menuPredecessor, int screenHeightMax)
{
double factor = 1;
if (NativeMethods.IsTouchEnabled())
{
factor = 1.5;
}
if (menuPredecessor == null)
{
if (dgv.Tag == null && dgv.Rows.Count > 0)
{
// Find row size based on content and apply factor
dgv.AutoResizeRows();
dgv.RowTemplate.Height = (int)(dgv.Rows[0].Height * factor);
dgv.Tag = true;
}
}
else
{
// Take over the height from predecessor menu
dgv.RowTemplate.Height = menuPredecessor.GetDataGridView().RowTemplate.Height;
dgv.Tag = true;
}
// Patch size of each row
foreach (DataGridViewRow row in dgv.Rows)
{
row.Height = dgv.RowTemplate.Height;
}
DataTable data = (DataTable)dgv.DataSource;
if (string.IsNullOrEmpty(data.DefaultView.RowFilter))
{
int dgvHeight = dgv.Rows.GetRowsHeight(DataGridViewElementStates.None); // Height of all rows
int dgvHeightMax = screenHeightMax - (Height - dgv.Height); // except dgv
if (dgvHeight > dgvHeightMax)
{
// Make all rows fit into the screen
dgvHeight = dgvHeightMax;
}
dgv.Height = dgvHeight;
}
}
private void AdjustDataGridViewWidth()
{
DataGridViewExtensions.FastAutoSizeColumns(dgv);