From 514638cd9d0cbcf8602af1386cc430d2b9108082 Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 23 Oct 2024 16:15:07 -0400 Subject: [PATCH] Fix NavigatorWindow placement (#1630) #1600 --- OneMore/Commands/Navigator/NavigatorWindow.cs | 82 ++++++++++++++++--- .../Helpers/Extensions/ScreenExtensions.cs | 23 ++++-- OneMore/UI/MoreForm.cs | 19 ++++- 3 files changed, 101 insertions(+), 23 deletions(-) diff --git a/OneMore/Commands/Navigator/NavigatorWindow.cs b/OneMore/Commands/Navigator/NavigatorWindow.cs index ae5242a12e..b98cc112fc 100644 --- a/OneMore/Commands/Navigator/NavigatorWindow.cs +++ b/OneMore/Commands/Navigator/NavigatorWindow.cs @@ -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; @@ -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"); @@ -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("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)); @@ -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) @@ -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; @@ -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); @@ -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) { diff --git a/OneMore/Helpers/Extensions/ScreenExtensions.cs b/OneMore/Helpers/Extensions/ScreenExtensions.cs index 6e6d367b31..29b223b666 100644 --- a/OneMore/Helpers/Extensions/ScreenExtensions.cs +++ b/OneMore/Helpers/Extensions/ScreenExtensions.cs @@ -10,21 +10,28 @@ namespace River.OneMoreAddIn.Helpers.Extensions internal static class ScreenExtensions { - private const int ReasonableMargin = 20; + public const int ReasonableMargin = 20; + /// + /// 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. + /// + /// The screen within which to corral the form + /// The form to be corralled + /// 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 diff --git a/OneMore/UI/MoreForm.cs b/OneMore/UI/MoreForm.cs index 3661b9b6d4..d2168049cf 100644 --- a/OneMore/UI/MoreForm.cs +++ b/OneMore/UI/MoreForm.cs @@ -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); @@ -203,9 +203,6 @@ static void LoadControls(Control.ControlCollection controls) } #endregion - //logger.WriteLine("onload"); - base.OnLoad(e); - if (ThemeEnabled) { manager.InitializeTheme(this); @@ -213,6 +210,7 @@ static void LoadControls(Control.ControlCollection controls) LoadControls(Controls); + //logger.WriteLine($"MoreForm.OnLoad try focus"); TryFocus(); // RunModeless has already set location so don't repeat that here and only set @@ -220,11 +218,16 @@ static void LoadControls(Control.ControlCollection controls) // 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?"); + /***** ********************************************************** *****/ /***** ********************************************************** *****/ /***** *****/ @@ -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}"); } } @@ -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"); }