From 04818d52f88ded7357f181311b618654a3fe598f Mon Sep 17 00:00:00 2001 From: Mostafa Date: Tue, 17 Feb 2026 17:51:08 +0200 Subject: [PATCH 1/2] Fix BackstageView popout issues: window closing logic, missing icon, and code cleanup --- .../Controls/BackstageView/BackstageView.cs | 114 ++++++++++++------ 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/ExtLibs/Controls/BackstageView/BackstageView.cs b/ExtLibs/Controls/BackstageView/BackstageView.cs index 2345b6beaf..72b179a92d 100644 --- a/ExtLibs/Controls/BackstageView/BackstageView.cs +++ b/ExtLibs/Controls/BackstageView/BackstageView.cs @@ -10,7 +10,8 @@ namespace MissionPlanner.Controls.BackstageView { /// - /// A Control to somewhat emulate the 'backstage view' as in MS Office 2010 + /// A Control to emulate the 'backstage view' (File Menu style) seen in MS Office 2010/2013. + /// Handles navigation between different configuration and setup screens. /// /// /// 'Tabs' are added as a control in a @@ -61,6 +62,7 @@ public int WidthMenu } } + // Tracks the currently popped-out page (if any) private BackstageViewPage popoutPage = null; private int ButtonTopPos = 0; @@ -75,8 +77,6 @@ public BackstageView() pnlMenu.BackColor = _buttonsAreaBgColor; pnlMenu.PencilBorderColor = _buttonsAreaPencilColor; pnlMenu.GradColor = this.BackColor; - - } public void UpdateDisplay() @@ -86,7 +86,6 @@ public void UpdateDisplay() if (!itemType.Show) continue; - if (itemType.Page != null) { itemType.Page.Location = new Point(0, 0); @@ -127,7 +126,6 @@ public Color ButtonsAreaPencilColor } } - [Description("Background color for the buttons region"), Category("Appearance")] [DefaultValue(typeof(Color), "White")] public Color ButtonsAreaBgColor @@ -234,21 +232,19 @@ private void CreateLinkButton(BackstageViewPage page, bool haschild = false, boo } var lnkButton = new BackstageViewButton - { - Text = label, - Tag = page, - Top = ButtonTopPos, - // Top = _items.TakeWhile(i => i != page).Sum(i => i.Spacing), - Width = this.pnlMenu.Width, - Height = ButtonHeight + heightextra, - ContentPageColor = this.BackColor, - PencilBorderColor = _buttonsAreaPencilColor, - SelectedTextColor = _selectedTextColor, - UnSelectedTextColor = _unSelectedTextColor, - HighlightColor1 = _highlightColor1, - HighlightColor2 = _highlightColor2, - //Dock = DockStyle.Bottom - }; + { + Text = label, + Tag = page, + Top = ButtonTopPos, + Width = this.pnlMenu.Width, + Height = ButtonHeight + heightextra, + ContentPageColor = this.BackColor, + PencilBorderColor = _buttonsAreaPencilColor, + SelectedTextColor = _selectedTextColor, + UnSelectedTextColor = _unSelectedTextColor, + HighlightColor1 = _highlightColor1, + HighlightColor2 = _highlightColor2, + }; pnlMenu.Controls.Add(lnkButton); lnkButton.Click += this.ButtonClick; @@ -331,7 +327,6 @@ public void DrawMenu(BackstageViewPage CurrentPage, bool force = false) } continue; } - } else { @@ -355,7 +350,6 @@ private bool PageHasChildren(BackstageViewPage parent) } } } - return false; } @@ -374,17 +368,45 @@ private void UpdateButtonAppearance() } } - /* - * Experimental - double clicking a button will spawn it out into a new form - * Care must be given to lifecycle here - two pages can now be interacted with - * 'simultaneously' - */ + /// + /// Experimental - double clicking a button will spawn it out into a new form + /// Allows interacting with two pages simultaneously. + /// private void lnkButton_DoubleClick(object sender, EventArgs e) { var backstageViewButton = ((BackstageViewButton)sender); var associatedPage = backstageViewButton.Tag as BackstageViewPage; var popoutForm = new Form(); + + // ---------------------------------------------------------------------- + // FIX for missing icon in pop-out window + // ---------------------------------------------------------------------- + + // Strategy 1: Attempt to copy the icon from the main parent form + if (this.FindForm() != null) + { + popoutForm.Icon = this.FindForm().Icon; + } + + // Strategy 2: If strategy 1 fails, try to extract the icon from the executable. + // This is wrapped in a preprocessor directive because ExtractAssociatedIcon is only available on Windows. +#if !NETSTANDARD + try + { + if (popoutForm.Icon == null) + { + popoutForm.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); + } + } + catch { /* Ignore failure to extract icon */ } +#endif + + // Ensure the icon is visible + popoutForm.ShowIcon = true; + + // ---------------------------------------------------------------------- + popoutForm.FormClosing += popoutForm_FormClosing; int maxright = 0, maxdown = 0; @@ -395,10 +417,9 @@ private void lnkButton_DoubleClick(object sender, EventArgs e) maxdown = Math.Max(ctl.Bottom, maxdown); } - // set the height to 0, so we can derive the header height in the next step popoutForm.Height = 0; - popoutForm.Size = new Size(maxright + 20, maxdown + 20 + popoutForm.Height); + popoutForm.Controls.Add(associatedPage.Page); popoutForm.Tag = associatedPage; @@ -432,6 +453,10 @@ private void ButtonClick(object sender, EventArgs e) this.ActivatePage(associatedPage); } + /// + /// Activates the selected page and displays it in the content panel. + /// Also handles closing any existing pop-out windows. + /// public void ActivatePage(BackstageViewPage associatedPage) { if (associatedPage == null) @@ -455,7 +480,7 @@ public void ActivatePage(BackstageViewPage associatedPage) { try { - ((IDeactivate) (_activePage.Page)).Deactivate(); + ((IDeactivate)(_activePage.Page)).Deactivate(); } catch (Exception ex) { @@ -463,14 +488,12 @@ public void ActivatePage(BackstageViewPage associatedPage) } } - // deactivate the old page - obsolete way of notifying activation - //_activePage.Page.Close(); - if (_activePage != null && _activePage.Page != null) _activePage.Page.Visible = false; try - { // if the button was on an expanded tab. when we leave it no longer exits + { + // if the button was on an expanded tab. when we leave it no longer exits if (_activePage != null) { var oldButton = this.pnlMenu.Controls.OfType().Single(b => b.Tag == _activePage); @@ -484,19 +507,34 @@ public void ActivatePage(BackstageViewPage associatedPage) associatedPage.Page.ResumeLayout(false); this.ResumeLayout(false); + // show it associatedPage.Page.Visible = true; + // --------------------------------------------------------- + // FIX for Issue #3633: Pop-out window not closing when re-docking + // --------------------------------------------------------- + // If any page is currently popped out in an external window, close it + // before navigating to prevent leaving an empty "ghost" window. + if (popoutPage != null) + { + Form parentWindow = popoutPage.Page.Parent as Form; + if (parentWindow != null) + { + parentWindow.Close(); + } + } + // --------------------------------------------------------- + if (!pnlPages.Controls.Contains(associatedPage.Page)) this.pnlPages.Controls.Add(associatedPage.Page); - // new way of notifying activation. Goal is to get rid of BackStageViewContentPanel - // so plain old user controls can be added + // new way of notifying activation. if (associatedPage.Page is IActivate) { try { - ((IActivate) (associatedPage.Page)).Activate(); + ((IActivate)(associatedPage.Page)).Activate(); } catch (Exception ex) { @@ -544,7 +582,7 @@ protected override void OnPaint(PaintEventArgs e) { try { - ((IDeactivate) ((BackstageViewPage) (page)).Page).Deactivate(); + ((IDeactivate)((BackstageViewPage)(page)).Page).Deactivate(); } catch (Exception ex) { From 4bb7b211271464fde36eabcc8675aa0c739913f0 Mon Sep 17 00:00:00 2001 From: Mostafa Elsehy <167577346+MostafaElsehy@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:48:01 +0200 Subject: [PATCH 2/2] Update ExtLibs/Controls/BackstageView/BackstageView.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- ExtLibs/Controls/BackstageView/BackstageView.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ExtLibs/Controls/BackstageView/BackstageView.cs b/ExtLibs/Controls/BackstageView/BackstageView.cs index 72b179a92d..e23602e91c 100644 --- a/ExtLibs/Controls/BackstageView/BackstageView.cs +++ b/ExtLibs/Controls/BackstageView/BackstageView.cs @@ -514,15 +514,19 @@ public void ActivatePage(BackstageViewPage associatedPage) // --------------------------------------------------------- // FIX for Issue #3633: Pop-out window not closing when re-docking // --------------------------------------------------------- - // If any page is currently popped out in an external window, close it - // before navigating to prevent leaving an empty "ghost" window. - if (popoutPage != null) + // If a different page is currently popped out in an external window, + // close it before navigating to prevent leaving an empty "ghost" window. + if (popoutPage != null && popoutPage != associatedPage) { Form parentWindow = popoutPage.Page.Parent as Form; - if (parentWindow != null) + if (parentWindow != null && !parentWindow.IsDisposed) { parentWindow.Close(); } + + // Reset the popped-out page reference so we don't repeatedly + // attempt to close an already-closed window on subsequent navigations. + popoutPage = null; } // ---------------------------------------------------------