diff --git a/tools/DevDiagnostics/DevHome.DevDiagnostics/Controls/ThemeAwareWindow.cs b/tools/DevDiagnostics/DevHome.DevDiagnostics/Controls/ThemeAwareWindow.cs new file mode 100644 index 0000000000..5880a64db0 --- /dev/null +++ b/tools/DevDiagnostics/DevHome.DevDiagnostics/Controls/ThemeAwareWindow.cs @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.UI; +using Microsoft.UI.Dispatching; +using Microsoft.UI.Windowing; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Windows.UI; +using Windows.UI.ViewManagement; +using WinUIEx; + +namespace DevHome.DevDiagnostics.Controls; + +/* This class encapsulates the theme-awareness logic, including support for custom chrome buttons. + * The main BarWindow derives from ThemeAwareWindow. All internal tool windows and any other owned windows + * must follow the theme of the main BarWindow. To achieve this: + * 1. Derive the tool window from ThemeAwareWindow. + * 2. Define a grid or panel for the icon and title (because this window sets ExtendsContentIntoTitleBar + * and HideIconAndSystemMenu). + * 3. Add the tool window to the list of related windows for the BarWindow by calling AddRelatedWindow. + * 4. Remove the tool window from the list of related windows for the BarWindow when the tool window is closed. + * 5. See ClipboardMonitoringWindow for an example. + */ + +public class ThemeAwareWindow : WindowEx +{ + private readonly SolidColorBrush _darkModeActiveCaptionBrush; + private readonly SolidColorBrush _darkModeInactiveCaptionBrush; + private readonly SolidColorBrush _nonDarkModeActiveCaptionBrush; + private readonly SolidColorBrush _nonDarkModeInactiveCaptionBrush; + private readonly UISettings _uiSettings = new(); + private readonly DispatcherQueue _dispatcher; + + private WindowActivationState _currentActivationState = WindowActivationState.Deactivated; + + private List RelatedWindows { get; set; } = []; + + internal List @@ -216,4 +217,4 @@ - + diff --git a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/BarWindow.xaml.cs b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/BarWindow.xaml.cs index 8c7c74ff22..6254612bdd 100644 --- a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/BarWindow.xaml.cs +++ b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/BarWindow.xaml.cs @@ -5,22 +5,18 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; -using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using DevHome.Common.Extensions; -using DevHome.Common.Services; using DevHome.DevDiagnostics.Controls; using DevHome.DevDiagnostics.Helpers; using DevHome.DevDiagnostics.Models; using DevHome.DevDiagnostics.Properties; using DevHome.DevDiagnostics.ViewModels; -using Microsoft.UI; using Microsoft.UI.Input; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media; using Serilog; using Windows.Foundation; using Windows.UI.ViewManagement; @@ -36,7 +32,7 @@ namespace DevHome.DevDiagnostics; -public partial class BarWindow : WindowEx +public partial class BarWindow : ThemeAwareWindow { private enum PinOption { @@ -49,29 +45,19 @@ private enum PinOption private const string ManageToolsButtonText = "\uec7a"; // DeveloperTools private static readonly ILogger _log = Log.ForContext("SourceContext", nameof(BarWindow)); - private readonly string _aliasDisabledDialogTitle = CommonHelper.GetLocalizedString("AliasDisabledDialogTitle"); - private readonly string _aliasDisabledDialogContent = CommonHelper.GetLocalizedString("AliasDisabledDialogContent"); - private readonly string _aliasDisabledDialogButtonText = CommonHelper.GetLocalizedString("AliasDisabledDialogButtonText"); - - private readonly string _pinMenuItemText = CommonHelper.GetLocalizedString("PinMenuItemText"); - private readonly string _unpinMenuItemText = CommonHelper.GetLocalizedString("UnpinMenuItemRawText"); - private readonly string _unregisterMenuItemText = CommonHelper.GetLocalizedString("UnregisterMenuItemRawText"); - private readonly string _manageToolsMenuItemText = CommonHelper.GetLocalizedString("ManageExternalToolsMenuText"); + private readonly string _aliasDisabledDialogTitle = GetLocalizedString("AliasDisabledDialogTitle"); + private readonly string _aliasDisabledDialogContent = GetLocalizedString("AliasDisabledDialogContent"); + private readonly string _aliasDisabledDialogButtonText = GetLocalizedString("AliasDisabledDialogButtonText"); + private readonly string _pinMenuItemText = GetLocalizedString("PinMenuItemText"); + private readonly string _unpinMenuItemText = GetLocalizedString("UnpinMenuItemRawText"); + private readonly string _unregisterMenuItemText = GetLocalizedString("UnregisterMenuItemRawText"); + private readonly string _manageToolsMenuItemText = GetLocalizedString("ManageExternalToolsMenuText"); private readonly Settings _settings = Settings.Default; private readonly BarWindowViewModel _viewModel; - private readonly UISettings _uiSettings = new(); - private readonly ExternalToolsHelper _externalTools; private readonly InternalToolsHelper _internalTools; - private readonly SolidColorBrush _darkModeActiveCaptionBrush; - private readonly SolidColorBrush _darkModeDeactiveCaptionBrush; - private readonly SolidColorBrush _nonDarkModeActiveCaptionBrush; - private readonly SolidColorBrush _nonDarkModeDeactiveCaptionBrush; - - private WindowActivationState _currentActivationState = WindowActivationState.Deactivated; - // Constants that control window sizes private const int WindowPositionOffsetY = 30; private const int FloatingHorizontalBarHeight = 90; @@ -79,15 +65,12 @@ private enum PinOption // Default size of the expanded view as a percentage of the screen size private const float DefaultExpandedViewHeightofScreen = 0.9f; - internal HWND ThisHwnd { get; private set; } + private float _previousCustomTitleBarOffset; - internal ClipboardMonitor? ClipboardMonitor { get; private set; } + internal HWND ThisHwnd { get; private set; } - private readonly Microsoft.UI.Dispatching.DispatcherQueue _dispatcher; private readonly object _parentProcessHwndLock = new(); - private float _previousCustomTitleBarOffset; - private HWND? _parentProcessHwnd; public BarWindow() @@ -95,41 +78,17 @@ public BarWindow() _viewModel = new BarWindowViewModel(); _externalTools = Application.Current.GetService(); _internalTools = Application.Current.GetService(); - _dispatcher = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); - Title = CommonHelper.GetLocalizedString("DDDisplayName"); + Title = GetLocalizedString("DDDisplayName"); InitializeComponent(); _viewModel.PropertyChanged += ViewModel_PropertyChanged; - ExtendsContentIntoTitleBar = true; - AppWindow.TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu; - ExpandCollapseLayoutButtonText.Text = _viewModel.ShowingExpandedContent ? CollapseButtonText : ExpandButtonText; + CustomTitleBarButtons.Add(ExpandCollapseLayoutButton); - // Precreate the brushes for the caption buttons - // In Dark Mode, the active state is white, and the deactive state is translucent white - // In Light Mode, the active state is black, and the deactive state is translucent black - Windows.UI.Color color = Colors.White; - _darkModeActiveCaptionBrush = new SolidColorBrush(color); - color.A = 0x66; - _darkModeDeactiveCaptionBrush = new SolidColorBrush(color); - - color = Colors.Black; - _nonDarkModeActiveCaptionBrush = new SolidColorBrush(color); - color.A = 0x66; - _nonDarkModeDeactiveCaptionBrush = new SolidColorBrush(color); - - _uiSettings.ColorValuesChanged += (sender, args) => - { - _dispatcher.TryEnqueue(() => - { - ApplySystemThemeToCaptionButtons(); - }); - }; - - // Initialize the parent process HWND in the constructor to avoid re-entrancy on the UI thread + // Initialize the parent process HWND in the constructor to avoid re-entrancy on the UI thread GetParentProcessHWND(); - } + } private HWND? GetParentProcessHWND() { @@ -142,8 +101,8 @@ public BarWindow() return _parentProcessHwnd; } - } - + } + private void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(BarWindowViewModel.ShowingExpandedContent)) @@ -390,12 +349,10 @@ public void SetRegionsForTitleBar() var transform = ChromeButtonPanel.TransformToVisual(null); var bounds = transform.TransformBounds(new Rect(0, 0, ChromeButtonPanel.ActualWidth, ChromeButtonPanel.ActualHeight)); - Windows.Graphics.RectInt32 chromeButtonsRect = WindowHelper.GetRect(bounds, scaleAdjustment); - + var chromeButtonsRect = GetRect(bounds, scaleAdjustment); var rectArray = new Windows.Graphics.RectInt32[] { chromeButtonsRect }; - InputNonClientPointerSource nonClientInputSrc = - InputNonClientPointerSource.GetForWindowId(AppWindow.Id); + var nonClientInputSrc = InputNonClientPointerSource.GetForWindowId(AppWindow.Id); nonClientInputSrc.SetRegionRects(NonClientRegionKind.Passthrough, rectArray); } @@ -513,27 +470,6 @@ private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e } } - internal void SetRequestedTheme(ElementTheme theme) - { - if (Content is FrameworkElement rootElement) - { - rootElement.RequestedTheme = theme; - - if (theme == ElementTheme.Dark) - { - SetCaptionButtonColors(Colors.White); - } - else if (theme == ElementTheme.Light) - { - SetCaptionButtonColors(Colors.Black); - } - else - { - ApplySystemThemeToCaptionButtons(); - } - } - } - private void ExpandLargeContentPanel() { // We're expanding. @@ -590,59 +526,6 @@ internal Frame GetFrame() return ExpandedViewControl.GetPageFrame(); } - // workaround as AppWindow TitleBar doesn't update caption button colors correctly when changed while app is running - // https://task.ms/44172495 - public void ApplySystemThemeToCaptionButtons() - { - if (Content is FrameworkElement rootElement) - { - Windows.UI.Color color; - if (rootElement.ActualTheme == ElementTheme.Dark) - { - color = Colors.White; - } - else - { - color = Colors.Black; - } - - SetCaptionButtonColors(color); - } - - return; - } - - public void SetCaptionButtonColors(Windows.UI.Color color) - { - AppWindow.TitleBar.ButtonForegroundColor = color; - UpdateCustomTitleBarButtonsTextColor(); - } - - private void Window_Activated(object sender, WindowActivatedEventArgs args) - { - // This follows the design guidance of dimming our title bar elements when the window isn't activated - // https://learn.microsoft.com/en-us/windows/apps/develop/title-bar#dim-the-title-bar-when-the-window-is-inactive - _currentActivationState = args.WindowActivationState; - UpdateCustomTitleBarButtonsTextColor(); - } - - private void UpdateCustomTitleBarButtonsTextColor() - { - FrameworkElement? rootElement = Content as FrameworkElement; - Debug.Assert(rootElement != null, "Expected Content to be a FrameworkElement"); - - if (_currentActivationState == WindowActivationState.Deactivated) - { - SolidColorBrush brush = (rootElement.ActualTheme == ElementTheme.Dark) ? _darkModeDeactiveCaptionBrush : _nonDarkModeDeactiveCaptionBrush; - ExpandCollapseLayoutButtonText.Foreground = brush; - } - else - { - SolidColorBrush brush = (rootElement.ActualTheme == ElementTheme.Dark) ? _darkModeActiveCaptionBrush : _nonDarkModeActiveCaptionBrush; - ExpandCollapseLayoutButtonText.Foreground = brush; - } - } - private void WindowEx_WindowStateChanged(object sender, WindowState e) { if (e.Equals(WindowState.Normal)) diff --git a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml index 764dfc904a..770d988429 100644 --- a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml +++ b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml @@ -1,5 +1,5 @@ - + TaskBarIcon="Images/dd.ico" + Closed="ThemeAwareWindow_Closed"> + + + + - + + + + + + + + + + - + diff --git a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml.cs b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml.cs index 376dc6b4dd..8d8789ba63 100644 --- a/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml.cs +++ b/tools/DevDiagnostics/DevHome.DevDiagnostics/Views/ClipboardMonitoringWindow.xaml.cs @@ -1,16 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using DevHome.DevDiagnostics.Helpers; -using WinUIEx; +using DevHome.Common.Extensions; +using DevHome.DevDiagnostics.Controls; +using Microsoft.UI.Xaml; namespace DevHome.DevDiagnostics.Views; -public sealed partial class ClipboardMonitoringWindow : WindowEx +public sealed partial class ClipboardMonitoringWindow : ThemeAwareWindow { public ClipboardMonitoringWindow() { InitializeComponent(); - Title = CommonHelper.GetLocalizedString("ClipboardMonitorWindowTitle"); + } + + private void ThemeAwareWindow_Closed(object sender, WindowEventArgs args) + { + var barWindow = Application.Current.GetService().DBarWindow; + barWindow?.RemoveRelatedWindow(this); } }