Skip to content

Commit

Permalink
Fix NavigatorWindow placement (#1630)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevencohn authored Oct 23, 2024
1 parent afc9286 commit 514638c
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 23 deletions.
82 changes: 71 additions & 11 deletions OneMore/Commands/Navigator/NavigatorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ namespace River.OneMoreAddIn.Commands

internal partial class NavigatorWindow : MoreForm
{
private const int WindowMargin = 20;
private const int WindowMargin = ScreenExtensions.ReasonableMargin;
private const int HeaderIndent = 18;
private const int MinimizedBounds = -32000;

private static string visitedID;

private Screen screen;
private Point corral;
private Rectangle corral;
private Point location;
private bool minimized;
private readonly int depth;
Expand Down Expand Up @@ -111,7 +111,11 @@ public NavigatorWindow()

protected override void OnLoad(EventArgs e)
{
//logger.WriteLine($"NavigatorWindow.OnLoad calling base...");

base.OnLoad(e);
//logger.WriteLine($"NavigatorWindow.OnLoad after base");

BackColor = manager.GetColor("Control");

var viewColor = manager.GetColor("ListView");
Expand All @@ -132,45 +136,80 @@ protected override void OnLoad(EventArgs e)
#region Window Management
private async void PositionOnLoad(object sender, EventArgs e)
{
//logger.WriteLine($"NavigatorWindow.PositionOnLoad");

// deal with primary/secondary displays in either duplicate or extended mode...
// Load is invoked prior to SizeChanged

await using var one = new OneNote();
screen = Screen.FromHandle(one.WindowHandle);
screen = null;

var settings = new SettingsProvider().GetCollection("navigator");
var device = settings.Get<string>("device");
if (device is not null)
{
screen = Array.Find(Screen.AllScreens, s => s.DeviceName == device);
}

if (screen is null)
{
await using var one = new OneNote();
screen = Screen.FromHandle(one.WindowHandle);
}

//logger.WriteLine($"NavigatorWindow.PositionOnLoad screen primary:{screen.Primary} " +
// $"dev:{screen.DeviceName} bounds:{screen.Bounds.X}x{screen.Bounds.Y} " +
// $"Bounds:{screen.Bounds.Width}x{screen.Bounds.Height} " +
// $"WorkArea:{screen.WorkingArea.Width}x{screen.WorkingArea.Height}");

// move this window into the coordinate space of the active screen
Location = screen.WorkingArea.Location;
//logger.WriteLine($"NavigatorWindow.PositionOnLoad location:{location.X}x{location.Y}");

corral = screen.GetBoundedLocation(this);
corral = GetCorral(screen);

var settings = new SettingsProvider().GetCollection("navigator");
if (settings.Contains("left") && settings.Contains("top"))
{
Left = settings.Get("left", Left);
Top = settings.Get("top", Top);
//logger.WriteLine($"NavigatorWindow.PositionOnLoad setting left:{Left} Top:{Top}");
}
else
{
// set to corral origin regardless of whether "corralled" is set
Left = corral.X;
Top = SystemInformation.CaptionHeight + WindowMargin;
Top = corral.Y;
//logger.WriteLine($"NavigatorWindow.PositionOnLoad corral left:{Left} Top:{Top}");

if (CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft)
{
Left = WindowMargin;
//logger.WriteLine($"NavigatorWindow.PositionOnLoad corral RTL left:{Left} Top:{Top}");
}
}

// it's possible that screen resolution has changed since settings were saved
// and that left/top is now off the visible screen...
if (Left > screen.WorkingArea.Width) Left = WindowMargin;
if (Top > screen.WorkingArea.Height) Top = WindowMargin;
if (Left > screen.WorkingArea.Right)
{
Left = WindowMargin;
//logger.WriteLine($"NavigatorWindow.PositionOnLoad override Left:{Left}");
}

if (Top > screen.WorkingArea.Bottom)
{
Top = WindowMargin;
//logger.WriteLine($"NavigatorWindow.PositionOnLoad override Top:{Top}");
}

if (settings.Contains("width") && settings.Contains("height"))
{
Width = settings.Get("width", Width);
Height = settings.Get("height", Height);
//logger.WriteLine($"NavigatorWindow.PositionOnLoad width:{Width} height:{Height}");
}

//logger.WriteLine($"NavigatorWindow.PositionOnLoad data...");

// designer defines width but height is calculated
MaximumSize = new Size(MaximumSize.Width, screen.WorkingArea.Height - (WindowMargin * 2));

Expand All @@ -188,6 +227,15 @@ private async void PositionOnLoad(object sender, EventArgs e)
}


private Rectangle GetCorral(Screen screen)
{
var bounds = screen.GetBoundedLocation(this);
var left = screen.WorkingArea.X + WindowMargin;
var top = screen.WorkingArea.Top + WindowMargin + SystemInformation.CaptionHeight;
return new Rectangle(left, top, bounds.X - left, bounds.Y - top);
}


private void SetLimitsOnSizeChanged(object sender, EventArgs e)
{
if (screen == null)
Expand All @@ -197,7 +245,7 @@ private void SetLimitsOnSizeChanged(object sender, EventArgs e)
}

// SizeChanged is invoked after Load which sets screenArea
corral = screen.GetBoundedLocation(this);
corral = GetCorral(screen);

var rowWidth = Width - SystemInformation.VerticalScrollBarWidth * 2;

Expand Down Expand Up @@ -292,8 +340,20 @@ private void SaveOnFormClosing(object sender, FormClosingEventArgs e)
{
if (WindowState == FormWindowState.Normal)
{
screen = Array.Find(Screen.AllScreens, s =>
Left >= s.WorkingArea.Left && Left <= s.WorkingArea.Right &&
Top >= s.WorkingArea.Top && Top <= s.WorkingArea.Bottom);

screen ??= Array.Find(Screen.AllScreens, s => s.Primary);

var settings = new SettingsProvider();
var collection = settings.GetCollection("navigator");

if (screen is not null)
{
collection.Add("device", screen.DeviceName);
}

collection.Add("left", Left);
collection.Add("top", Top);
collection.Add("width", Width);
Expand Down Expand Up @@ -441,7 +501,7 @@ private async Task UpdateTitles(Page page)
}


private bool TitleChanged(ListView box, Page page)
private static bool TitleChanged(ListView box, Page page)
{
foreach (IMoreHostItem host in box.Items)
{
Expand Down
23 changes: 15 additions & 8 deletions OneMore/Helpers/Extensions/ScreenExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,28 @@ namespace River.OneMoreAddIn.Helpers.Extensions

internal static class ScreenExtensions
{
private const int ReasonableMargin = 20;
public const int ReasonableMargin = 20;


/// <summary>
/// Given a form on a screen (e.g. NavigatorWindow), calculate the maximum Left/Top
/// coordinate for that form on the screen as if it were corralled the screen's workarea
/// with a reasonable margin.
/// </summary>
/// <param name="screen">The screen within which to corral the form</param>
/// <param name="form">The form to be corralled</param>
/// <returns></returns>
public static Point GetBoundedLocation(this Screen screen, Form form)
{
// While Bounds is the entire screen with zero-based coordinates from upper left,
// WorkingArea is the subset of Bound minus space for the taskbar; so it shares the
// same origin of upper-left of screen but Top,Left,Right,Bottom may be adjusted
// to accomodate the position of the taskbar...
// screen.Bounds is the entire canvas of the display including pinned taskbar.
// screen.WorkArea is the working canvas of the display excluding the taskbar.
// Both Bounds and WorkArea have the same Left/Top origin; but note that the work
// area of a secondary extended display is relative to the primary display so its
// left-most x coordinate may be greather than zero.

// useable area of display, excluding taskbar, e.g. the "desktop"
var area = screen.WorkingArea;

// Note also that the working area of an secondary extended display is relative to
// the primary display so its left-most X coordinate may be greater than zero...

return new Point(
area.X + (area.Width - form.Width - ReasonableMargin),
area.Height - form.Height - ReasonableMargin
Expand Down
19 changes: 15 additions & 4 deletions OneMore/UI/MoreForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ So the conclusion is that the code below is a careful balance that eliminates th

protected override void OnActivated(EventArgs e)
{
//logger.WriteLine($"activating [{Text}]");
//logger.WriteLine($"MoreForm.OnActivated [{Text}]");

base.OnActivated(e);

Expand Down Expand Up @@ -203,28 +203,31 @@ static void LoadControls(Control.ControlCollection controls)
}
#endregion

//logger.WriteLine("onload");
base.OnLoad(e);

if (ThemeEnabled)
{
manager.InitializeTheme(this);
}

LoadControls(Controls);

//logger.WriteLine($"MoreForm.OnLoad try focus");
TryFocus();

// RunModeless has already set location so don't repeat that here and only set
// location if inheritor hasn't declined by setting it to zero. Also, we're doing
// this in OnLoad so it doesn't visually "jump" as it would if done in OnShown
if (DesignMode || modeless)
{
//logger.WriteLine($"MoreForm.OnLoad calling base due to modeless...");
base.OnLoad(e);
//logger.WriteLine($"MoreForm.OnLoad returning due to modeless");
return;
}

if (!ManualLocation && StartPosition == FormStartPosition.Manual)
{
//logger.WriteLine($"MoreForm.OnLoad manual manual?");

/***** ********************************************************** *****/
/***** ********************************************************** *****/
/***** *****/
Expand All @@ -248,6 +251,8 @@ static void LoadControls(Control.ControlCollection controls)
bounds.Top + (bounds.Bottom - bounds.Top) / 2);

Location = new Point(center.X - (Width / 2), center.Y - (Height / 2));

//logger.WriteLine($"MoreForm.OnLoad center point {Location.X}x{Location.Y}");
}
}

Expand All @@ -258,7 +263,13 @@ static void LoadControls(Control.ControlCollection controls)
var y = Location.Y + VerticalOffset;

Location = new Point(x, y < 0 ? 0 : y);

//logger.WriteLine($"MoreForm.OnLoad vertical offset {Location.X}x{Location.Y}");
}

//logger.WriteLine($"MoreForm.OnLoad calling base...");
base.OnLoad(e);
//logger.WriteLine($"MoreForm.OnLoad after base");
}


Expand Down

0 comments on commit 514638c

Please sign in to comment.