mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 03:07:04 +02:00
Introduce new utility PowerDisplay to control your monitor settings (#42642)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Introduce a new PowerToys' module PowerDisplay to let user can control their monitor settings without touching monitor's button. Support feature list: Common: 1. Profiles support 2. Integration with LightSwitch (auto switch profile when theme change) 3. TrayIcon 4. Save and restore settings when startup 5. Shortcut 6. Rotation 7. GPO support 8. Auto re-discovery monitor when plugging and unplugging monitors. 9. Identify Monitors 10. Quick profile switch Especially for DDC/CI monitor: 1. Brightness 2. Contrast 3. Volume 4. Color temperature (preset profile) 5. Input source 6. Power State (poweroff) Design doc: https://github.com/microsoft/PowerToys/blob/yuleng/display/pr/3/doc/devdocs/modules/powerdisplay/design.md AOT compatibility: I designed this module for AOT from the start, so I'm pretty sure at least 95% of it is AOT compatible. But unfortunately, PowerToys still have a AOT blocker to block this module publish with AOT. Currently PowerToys will check the .net file version (file version not lib version) to avoid crash. So, all modules should reference Common.UI or add UseWPF to avoid overwrite the .net file with different version (which may cause crash). Todo: - [ ] BugBash - [ ] Icon - [ ] IdentifyWindow UI improvement Demo Main UI: <img width="546" height="671" alt="image" src="https://github.com/user-attachments/assets/b0ad9ac5-8000-4365-a192-ab8c2d66d4f1" /> Input Source: <img width="536" height="674" alt="image" src="https://github.com/user-attachments/assets/80f9ccd7-4f8c-4201-b177-cc86c5bcc9e3" /> Settings UI: <img width="1581" height="1191" alt="image" src="https://github.com/user-attachments/assets/6a82e4bb-8f96-4f28-abf9-d7c45e1c8ef7" /> <img width="1525" height="1146" alt="image" src="https://github.com/user-attachments/assets/aae81e65-08fd-453a-bf52-02a74f2fdea0" /> Closes: #42942 #42678 #41117 #38109 #35564 #34932 #28500 #1052 #18149 <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #1052 - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end-user-facing strings can be localized - [x] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed --------- Co-authored-by: Yu Leng <yuleng@microsoft.com> Co-authored-by: Niels Laute <niels.laute@live.nl> Co-authored-by: moooyo <lengyuchn@gmail.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -415,6 +415,7 @@ namespace Microsoft.PowerToys.Settings.UI
|
||||
case "Workspaces": return typeof(WorkspacesPage);
|
||||
case "CmdPal": return typeof(CmdPalPage);
|
||||
case "ZoomIt": return typeof(ZoomItPage);
|
||||
case "PowerDisplay": return typeof(PowerDisplayPage);
|
||||
default:
|
||||
// Fallback to Dashboard
|
||||
Debug.Assert(false, "Unexpected SettingsWindow argument value");
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<Page
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.OOBE.Views.OobePowerDisplay"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:OOBEPageControl x:Uid="Oobe_PowerDisplay" HeroImage="ms-appx:///Assets/Settings/Modules/OOBE/PowerDisplay.gif">
|
||||
<controls:OOBEPageControl.PageContent>
|
||||
<StackPanel Orientation="Vertical" Spacing="12">
|
||||
<TextBlock x:Uid="Oobe_HowToLaunch" Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
|
||||
<controls:ShortcutWithTextLabelControl x:Name="HotkeyActivation" x:Uid="Oobe_PowerDisplay_Activation" />
|
||||
|
||||
<TextBlock x:Uid="Oobe_TipsAndTricks" Style="{ThemeResource OobeSubtitleStyle}" />
|
||||
|
||||
<tkcontrols:MarkdownTextBlock x:Uid="Oobe_PowerDisplay_TipsAndTricks" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button
|
||||
x:Uid="Launch_PowerDisplay"
|
||||
Click="Launch_PowerDisplay_Click"
|
||||
Style="{StaticResource AccentButtonStyle}" />
|
||||
<Button x:Uid="OOBE_Settings" Click="SettingsLaunchButton_Click" />
|
||||
|
||||
<HyperlinkButton NavigateUri="https://aka.ms/PowerToysOverview_PowerDisplay" Style="{StaticResource TextButtonStyle}">
|
||||
<TextBlock x:Uid="LearnMore_PowerDisplay" TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</controls:OOBEPageControl.PageContent>
|
||||
</controls:OOBEPageControl>
|
||||
</Page>
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Threading;
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
using Microsoft.PowerToys.Settings.UI.Views;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using PowerToys.Interop;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class OobePowerDisplay : Page
|
||||
{
|
||||
public OobePowerToysModule ViewModel { get; set; }
|
||||
|
||||
public OobePowerDisplay()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.PowerDisplay]);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void Launch_PowerDisplay_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.TogglePowerDisplayEvent()))
|
||||
{
|
||||
eventHandle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.OpenMainWindowCallback != null)
|
||||
{
|
||||
OobeShellPage.OpenMainWindowCallback(typeof(PowerDisplayPage));
|
||||
}
|
||||
|
||||
ViewModel.LogOpeningSettingsEvent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogOpeningModuleEvent();
|
||||
HotkeyActivation.Keys = SettingsRepository<PowerDisplaySettings>.GetInstance(SettingsUtils.Default).SettingsConfig.Properties.ActivationShortcut.GetKeysList();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ViewModel.LogClosingModuleEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,10 @@
|
||||
x:Uid="Shell_MouseUtilities"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseUtils.png}"
|
||||
Tag="MouseUtils" />
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_PowerDisplay"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/PowerDisplay.png}"
|
||||
Tag="PowerDisplay" />
|
||||
<NavigationViewItem
|
||||
x:Uid="Shell_MouseWithoutBorders"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseWithoutBorders.png}"
|
||||
|
||||
@@ -206,6 +206,12 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
IsNew = false,
|
||||
});
|
||||
|
||||
Modules.Insert((int)PowerToysModules.PowerDisplay, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = "PowerDisplay",
|
||||
IsNew = true,
|
||||
});
|
||||
|
||||
Modules.Insert((int)PowerToysModules.NewPlus, new OobePowerToysModule()
|
||||
{
|
||||
ModuleName = "NewPlus",
|
||||
@@ -301,6 +307,7 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
case "Peek": NavigationFrame.Navigate(typeof(OobePeek)); break;
|
||||
case "NewPlus": NavigationFrame.Navigate(typeof(OobeNewPlus)); break;
|
||||
case "Workspaces": NavigationFrame.Navigate(typeof(OobeWorkspaces)); break;
|
||||
case "PowerDisplay": NavigationFrame.Navigate(typeof(OobePowerDisplay)); break;
|
||||
case "ZoomIt": NavigationFrame.Navigate(typeof(OobeZoomIt)); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,29 +191,83 @@
|
||||
IsOpen="True"
|
||||
Severity="Informational"
|
||||
Visibility="Collapsed" />
|
||||
<controls:SettingsGroup x:Uid="LightSwitch_BehaviorSettingsGroup" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="LightSwitch_ApplyDarkModeExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||
<controls:CheckBoxWithDescriptionControl
|
||||
x:Uid="LightSwitch_SystemCheckbox"
|
||||
AutomationProperties.AutomationId="ChangeSystemCheckbox_LightSwitch"
|
||||
IsChecked="{x:Bind ViewModel.ChangeSystem, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||
<controls:CheckBoxWithDescriptionControl
|
||||
x:Uid="LightSwitch_AppsCheckbox"
|
||||
AutomationProperties.AutomationId="ChangeAppsCheckbox_LightSwitch"
|
||||
IsChecked="{x:Bind ViewModel.ChangeApps, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
<!-- Force mode buttons -->
|
||||
<!--<tkcontrols:SettingsCard
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="LightSwitch_BehaviorSettingsGroup" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="LightSwitch_ApplyDarkModeExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||
<controls:CheckBoxWithDescriptionControl
|
||||
x:Uid="LightSwitch_SystemCheckbox"
|
||||
AutomationProperties.AutomationId="ChangeSystemCheckbox_LightSwitch"
|
||||
IsChecked="{x:Bind ViewModel.ChangeSystem, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard HorizontalContentAlignment="Stretch" ContentAlignment="Left">
|
||||
<controls:CheckBoxWithDescriptionControl
|
||||
x:Uid="LightSwitch_AppsCheckbox"
|
||||
AutomationProperties.AutomationId="ChangeAppsCheckbox_LightSwitch"
|
||||
IsChecked="{x:Bind ViewModel.ChangeApps, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
<InfoBar
|
||||
x:Name="PowerDisplayDisabledWarningBar"
|
||||
x:Uid="LightSwitch_PowerDisplayDisabledWarningBar"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
IsTabStop="True"
|
||||
Severity="Informational"
|
||||
Visibility="{x:Bind ViewModel.ShowPowerDisplayDisabledWarning, Mode=OneWay}">
|
||||
<InfoBar.ActionButton>
|
||||
<HyperlinkButton
|
||||
x:Uid="LightSwitch_NavigatePowerDisplaySettings"
|
||||
HorizontalAlignment="Right"
|
||||
Click="NavigatePowerDisplaySettings_Click" />
|
||||
</InfoBar.ActionButton>
|
||||
</InfoBar>
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="LightSwitch_ApplyMonitorSettingsExpander"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox
|
||||
x:Uid="LightSwitch_DarkModeProfileCheckbox"
|
||||
IsChecked="{x:Bind ViewModel.EnableDarkModeProfile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}" />
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
DisplayMemberPath="Name"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedDarkModeProfile, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox
|
||||
x:Uid="LightSwitch_LightModeProfileCheckbox"
|
||||
IsChecked="{x:Bind ViewModel.EnableLightModeProfile, Mode=TwoWay}"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}" />
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<ComboBox
|
||||
MinWidth="200"
|
||||
DisplayMemberPath="Name"
|
||||
IsEnabled="{x:Bind ViewModel.IsPowerDisplayEnabled, Mode=OneWay}"
|
||||
ItemsSource="{x:Bind ViewModel.AvailableProfiles, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedLightModeProfile, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
<!-- Force mode buttons -->
|
||||
<!--<tkcontrols:SettingsCard
|
||||
Header="Force mode now"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
Description="Apply light or dark mode immediately">
|
||||
@@ -227,24 +281,24 @@
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard>-->
|
||||
|
||||
<ContentDialog
|
||||
x:Name="LocationDialog"
|
||||
x:Uid="LightSwitch_LocationDialog"
|
||||
IsPrimaryButtonEnabled="False"
|
||||
IsSecondaryButtonEnabled="True"
|
||||
PrimaryButtonClick="LocationDialog_PrimaryButtonClick"
|
||||
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
|
||||
<Grid RowSpacing="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" MinHeight="64" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="LightSwitch_LocationDialog_Description"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<!--<AutoSuggestBox
|
||||
<ContentDialog
|
||||
x:Name="LocationDialog"
|
||||
x:Uid="LightSwitch_LocationDialog"
|
||||
IsPrimaryButtonEnabled="False"
|
||||
IsSecondaryButtonEnabled="True"
|
||||
PrimaryButtonClick="LocationDialog_PrimaryButtonClick"
|
||||
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
|
||||
<Grid RowSpacing="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" MinHeight="64" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="LightSwitch_LocationDialog_Description"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
TextWrapping="Wrap" />
|
||||
<!--<AutoSuggestBox
|
||||
x:Name="CityAutoSuggestBox"
|
||||
Grid.Row="1"
|
||||
Margin="0,16,0,8"
|
||||
@@ -272,100 +326,99 @@
|
||||
</AutoSuggestBox.ItemTemplate>
|
||||
</AutoSuggestBox>-->
|
||||
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,0"
|
||||
ColumnSpacing="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="124" />
|
||||
<ColumnDefinition Width="124" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<NumberBox
|
||||
x:Name="LatitudeBox"
|
||||
x:Uid="LightSwitch_LatitudeBox"
|
||||
AutomationProperties.AutomationId="LatitudeBox_LightSwitch"
|
||||
Maximum="90"
|
||||
Minimum="-90"
|
||||
ValueChanged="LatLonBox_ValueChanged"
|
||||
Value="{x:Bind ViewModel.LocationPanelLatitude, Mode=TwoWay}" />
|
||||
<NumberBox
|
||||
x:Name="LongitudeBox"
|
||||
x:Uid="LightSwitch_LongitudeBox"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="LongitudeBox_LightSwitch"
|
||||
Maximum="180"
|
||||
Minimum="-180"
|
||||
ValueChanged="LatLonBox_ValueChanged"
|
||||
Value="{x:Bind ViewModel.LocationPanelLongitude, Mode=TwoWay}" />
|
||||
<Button
|
||||
x:Name="SyncButton"
|
||||
x:Uid="LightSwitch_FindLocationAutomation"
|
||||
Grid.Column="2"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
AutomationProperties.AutomationId="SyncLocationButton_LightSwitch"
|
||||
Click="GetGeoLocation_Click">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="LightSwitch_FindLocation" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
<ProgressRing
|
||||
x:Name="SyncLoader"
|
||||
Grid.Row="2"
|
||||
Width="40"
|
||||
Height="40"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="False"
|
||||
Visibility="Collapsed" />
|
||||
<Grid
|
||||
x:Name="LocationResultPanel"
|
||||
Grid.Row="2"
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Margin="0,12,0,0"
|
||||
ColumnSpacing="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="124" />
|
||||
<ColumnDefinition Width="124" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<NumberBox
|
||||
x:Name="LatitudeBox"
|
||||
x:Uid="LightSwitch_LatitudeBox"
|
||||
AutomationProperties.AutomationId="LatitudeBox_LightSwitch"
|
||||
Maximum="90"
|
||||
Minimum="-90"
|
||||
ValueChanged="LatLonBox_ValueChanged"
|
||||
Value="{x:Bind ViewModel.LocationPanelLatitude, Mode=TwoWay}" />
|
||||
<NumberBox
|
||||
x:Name="LongitudeBox"
|
||||
x:Uid="LightSwitch_LongitudeBox"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="LongitudeBox_LightSwitch"
|
||||
Maximum="180"
|
||||
Minimum="-180"
|
||||
ValueChanged="LatLonBox_ValueChanged"
|
||||
Value="{x:Bind ViewModel.LocationPanelLongitude, Mode=TwoWay}" />
|
||||
<Button
|
||||
x:Name="SyncButton"
|
||||
x:Uid="LightSwitch_FindLocationAutomation"
|
||||
Grid.Column="2"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Bottom"
|
||||
ColumnSpacing="16"
|
||||
RowSpacing="12"
|
||||
Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<FontIcon FontSize="20" Glyph="">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="LightSwitch_SunriseTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
</FontIcon>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="SunriseText_LightSwitch"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind ViewModel.LocationPanelLightTime, Converter={StaticResource TimeSpanToFriendlyTimeConverter}, Mode=OneWay}"
|
||||
TextAlignment="Left" />
|
||||
<FontIcon
|
||||
Grid.Row="1"
|
||||
FontSize="20"
|
||||
Glyph="">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="LightSwitch_SunsetTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
</FontIcon>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="SunsetText_LightSwitch"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind ViewModel.LocationPanelDarkTime, Converter={StaticResource TimeSpanToFriendlyTimeConverter}, Mode=OneWay}"
|
||||
TextAlignment="Left" />
|
||||
</Grid>
|
||||
AutomationProperties.AutomationId="SyncLocationButton_LightSwitch"
|
||||
Click="GetGeoLocation_Click">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="LightSwitch_FindLocation" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
</controls:SettingsGroup>
|
||||
<ProgressRing
|
||||
x:Name="SyncLoader"
|
||||
Grid.Row="2"
|
||||
Width="40"
|
||||
Height="40"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="False"
|
||||
Visibility="Collapsed" />
|
||||
<Grid
|
||||
x:Name="LocationResultPanel"
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Bottom"
|
||||
ColumnSpacing="16"
|
||||
RowSpacing="12"
|
||||
Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<FontIcon FontSize="20" Glyph="">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="LightSwitch_SunriseTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
</FontIcon>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="SunriseText_LightSwitch"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind ViewModel.LocationPanelLightTime, Converter={StaticResource TimeSpanToFriendlyTimeConverter}, Mode=OneWay}"
|
||||
TextAlignment="Left" />
|
||||
<FontIcon
|
||||
Grid.Row="1"
|
||||
FontSize="20"
|
||||
Glyph="">
|
||||
<ToolTipService.ToolTip>
|
||||
<TextBlock x:Uid="LightSwitch_SunsetTooltip" />
|
||||
</ToolTipService.ToolTip>
|
||||
</FontIcon>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.AutomationId="SunsetText_LightSwitch"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind ViewModel.LocationPanelDarkTime, Converter={StaticResource TimeSpanToFriendlyTimeConverter}, Mode=OneWay}"
|
||||
TextAlignment="Left" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
@@ -380,5 +381,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
this.LocationWarningBar.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigatePowerDisplaySettings_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
ShellPage.Navigate(typeof(PowerDisplayPage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.PowerDisplayPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:library="using:Microsoft.PowerToys.Settings.UI.Library"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:pdmodels="using:PowerDisplay.Common.Models"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<controls:SettingsPageControl x:Uid="PowerDisplay" ModuleImageSource="ms-appx:///Assets/Settings/Modules/PowerDisplay.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
<controls:GPOInfoControl ShowWarning="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="PowerDisplay_Enable_PowerDisplay"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/PowerDisplay.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:GPOInfoControl>
|
||||
|
||||
<controls:SettingsGroup x:Uid="Shortcut" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_ActivationShortcut" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<controls:ShortcutControl MinWidth="{StaticResource SettingActionControlMinWidth}" HotkeySettings="{x:Bind Path=ViewModel.ActivationShortcut, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="PowerDisplay_Configuration_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard
|
||||
x:Uid="PowerDisplay_LaunchButtonControl"
|
||||
ActionIcon="{ui:FontIcon Glyph=}"
|
||||
Command="{x:Bind ViewModel.LaunchEventHandler}"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsClickEnabled="True" />
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_RestoreSettingsOnStartup" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch x:Uid="PowerDisplay_RestoreSettingsOnStartup_ToggleSwitch" IsOn="{x:Bind ViewModel.RestoreSettingsOnStartup, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_ShowSystemTrayIcon" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowSystemTrayIcon, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_MonitorRefreshDelay" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ComboBox
|
||||
MinWidth="120"
|
||||
ItemsSource="{x:Bind ViewModel.MonitorRefreshDelayOptions}"
|
||||
SelectedItem="{x:Bind ViewModel.MonitorRefreshDelay, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="PowerDisplay_FlyoutOptions_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_ShowProfileSwitcher" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowProfileSwitcher, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_ShowIdentifyMonitorsButton" HeaderIcon="{ui:FontIcon Glyph=}">
|
||||
<ToggleSwitch IsOn="{x:Bind ViewModel.ShowIdentifyMonitorsButton, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="PowerDisplay_Profiles_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander
|
||||
x:Uid="PowerDisplay_QuickProfiles"
|
||||
HeaderIcon="{ui:FontIcon Glyph=}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind ViewModel.Profiles, Mode=OneWay}">
|
||||
<tkcontrols:SettingsExpander.ItemTemplate>
|
||||
<DataTemplate x:DataType="pdmodels:PowerDisplayProfile">
|
||||
<tkcontrols:SettingsCard Header="{x:Bind Name}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<Button
|
||||
x:Uid="PowerDisplay_Profile_ApplyButton"
|
||||
Click="ProfileButton_Click"
|
||||
Tag="{x:Bind}" />
|
||||
<Button
|
||||
x:Uid="PowerDisplay_Profile_MoreButton"
|
||||
Content="{ui:FontIcon Glyph=,
|
||||
FontSize=16}"
|
||||
Style="{StaticResource SubtleButtonStyle}"
|
||||
Tag="{x:Bind}">
|
||||
<Button.Flyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem
|
||||
x:Uid="PowerDisplay_Profile_EditMenuItem"
|
||||
Click="EditProfile_Click"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tag="{x:Bind}" />
|
||||
<MenuFlyoutSeparator />
|
||||
<MenuFlyoutItem
|
||||
x:Uid="PowerDisplay_Profile_DeleteMenuItem"
|
||||
Click="DeleteProfile_Click"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tag="{x:Bind}" />
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</tkcontrols:SettingsCard>
|
||||
</DataTemplate>
|
||||
</tkcontrols:SettingsExpander.ItemTemplate>
|
||||
|
||||
<!-- Add profile button -->
|
||||
<Button x:Uid="PowerDisplay_AddProfileButton" Click="AddProfileButton_Click">
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_AddProfile_Text" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</controls:SettingsGroup>
|
||||
|
||||
<controls:SettingsGroup x:Uid="PowerDisplay_Monitors" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
|
||||
<!-- Empty state hint -->
|
||||
<TextBlock
|
||||
x:Uid="PowerDisplay_NoMonitorsDetected"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Visibility="{x:Bind ViewModel.HasMonitors, Mode=OneWay, Converter={StaticResource ReverseBoolToVisibilityConverter}}" />
|
||||
|
||||
<!-- Monitor list -->
|
||||
<ItemsControl
|
||||
x:Name="MonitorsList"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind ViewModel.Monitors, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.HasMonitors, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="library:MonitorInfo">
|
||||
<tkcontrols:SettingsExpander
|
||||
Margin="0,0,0,2"
|
||||
Description="{x:Bind Id, Mode=OneWay}"
|
||||
Header="{x:Bind DisplayName, Mode=OneWay}"
|
||||
IsExpanded="False">
|
||||
<tkcontrols:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="{x:Bind MonitorIconGlyph, Mode=OneWay}" />
|
||||
</tkcontrols:SettingsExpander.HeaderIcon>
|
||||
<TextBlock Text="{x:Bind CommunicationMethod, Mode=OneWay}" />
|
||||
<tkcontrols:SettingsExpander.ItemsHeader>
|
||||
<!-- Capabilities warning -->
|
||||
<InfoBar
|
||||
x:Uid="PowerDisplay_Monitor_CapabilitiesWarning"
|
||||
BorderThickness="0"
|
||||
CornerRadius="0"
|
||||
IsClosable="False"
|
||||
IsOpen="True"
|
||||
Severity="Warning"
|
||||
Visibility="{x:Bind ShowCapabilitiesWarning, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</tkcontrols:SettingsExpander.ItemsHeader>
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind SupportsContrast, Mode=OneWay}">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_EnableContrast" IsChecked="{x:Bind EnableContrast, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind SupportsVolume, Mode=OneWay}">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_EnableVolume" IsChecked="{x:Bind EnableVolume, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind SupportsInputSource, Mode=OneWay}">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_EnableInputSource" IsChecked="{x:Bind EnableInputSource, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_EnableRotation" IsChecked="{x:Bind EnableRotation, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind SupportsColorTemperature, Mode=OneWay}">
|
||||
<CheckBox
|
||||
x:Uid="PowerDisplay_Monitor_EnableColorTemperature"
|
||||
Click="EnableColorTemperature_Click"
|
||||
IsChecked="{x:Bind EnableColorTemperature, Mode=TwoWay}"
|
||||
Tag="{x:Bind}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left" IsEnabled="{x:Bind SupportsPowerState, Mode=OneWay}">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_EnablePowerState" IsChecked="{x:Bind EnablePowerState, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard ContentAlignment="Left">
|
||||
<CheckBox x:Uid="PowerDisplay_Monitor_HideMonitor" IsChecked="{x:Bind IsHidden, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<!-- VCP Capabilities -->
|
||||
<tkcontrols:SettingsCard x:Uid="PowerDisplay_Monitor_VcpCapabilities" Visibility="{x:Bind HasCapabilities, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Button
|
||||
x:Uid="PowerDisplay_Monitor_VcpDetails_Button"
|
||||
Content=""
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
Style="{StaticResource SubtleButtonStyle}">
|
||||
<Button.Flyout>
|
||||
<Flyout ShouldConstrainToRootBounds="False">
|
||||
<Grid Width="420">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Header with Copy Button -->
|
||||
<Grid Margin="0,0,0,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
x:Uid="PowerDisplay_Monitor_VcpCodes_Header"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold" />
|
||||
<Button
|
||||
x:Uid="PowerDisplay_Monitor_VcpCodes_CopyButton"
|
||||
Grid.Column="1"
|
||||
Padding="8,4"
|
||||
VerticalAlignment="Center"
|
||||
Click="CopyVcpCodes_Click"
|
||||
Tag="{x:Bind}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<FontIcon FontSize="12" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_Monitor_VcpCodes_CopyText" FontSize="12" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<!-- VCP Codes List -->
|
||||
<ScrollViewer
|
||||
Grid.Row="1"
|
||||
MaxHeight="480"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
HorizontalScrollMode="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl HorizontalAlignment="Stretch" ItemsSource="{x:Bind VcpCodesFormatted, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="library:VcpCodeDisplayInfo">
|
||||
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical">
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{x:Bind Title}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Margin="0,0,0,8"
|
||||
FontSize="12"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Text="{x:Bind Values}"
|
||||
TextWrapping="Wrap"
|
||||
Visibility="{x:Bind HasValues}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</controls:SettingsGroup>
|
||||
</StackPanel>
|
||||
</controls:SettingsPageControl.ModuleContent>
|
||||
<controls:SettingsPageControl.PrimaryLinks>
|
||||
<controls:PageLink x:Uid="LearnMore_PowerDisplay" Link="https://aka.ms/PowerToysOverview_PowerDisplay" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigablePage>
|
||||
@@ -0,0 +1,218 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using PowerDisplay.Common.Models;
|
||||
using PowerDisplay.Common.Utils;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class PowerDisplayPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private PowerDisplayViewModel ViewModel { get; set; }
|
||||
|
||||
public PowerDisplayPage()
|
||||
{
|
||||
var settingsUtils = SettingsUtils.Default;
|
||||
ViewModel = new PowerDisplayViewModel(
|
||||
settingsUtils,
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
SettingsRepository<PowerDisplaySettings>.GetInstance(settingsUtils),
|
||||
ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
InitializeComponent();
|
||||
Loaded += (s, e) => ViewModel.OnPageLoaded();
|
||||
}
|
||||
|
||||
public void RefreshEnabledState()
|
||||
{
|
||||
ViewModel.RefreshEnabledState();
|
||||
}
|
||||
|
||||
private void CopyVcpCodes_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.Tag is MonitorInfo monitor)
|
||||
{
|
||||
var vcpText = monitor.GetVcpCodesAsText();
|
||||
var dataPackage = new DataPackage();
|
||||
dataPackage.SetText(vcpText);
|
||||
Clipboard.SetContent(dataPackage);
|
||||
}
|
||||
}
|
||||
|
||||
// Profile button event handlers
|
||||
private void ProfileButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.Tag is PowerDisplayProfile profile)
|
||||
{
|
||||
ViewModel.ApplyProfile(profile);
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddProfileButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (ViewModel.Monitors == null || ViewModel.Monitors.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultName = GenerateDefaultProfileName();
|
||||
var dialog = new ProfileEditorDialog(ViewModel.Monitors, defaultName);
|
||||
dialog.XamlRoot = this.XamlRoot;
|
||||
|
||||
var result = await dialog.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary && dialog.ResultProfile != null)
|
||||
{
|
||||
ViewModel.CreateProfile(dialog.ResultProfile);
|
||||
}
|
||||
}
|
||||
|
||||
private async void EditProfile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = sender as MenuFlyoutItem;
|
||||
if (menuItem?.Tag is PowerDisplayProfile profile)
|
||||
{
|
||||
var dialog = new ProfileEditorDialog(ViewModel.Monitors, profile.Name);
|
||||
dialog.XamlRoot = this.XamlRoot;
|
||||
|
||||
// Pre-fill with existing profile settings
|
||||
dialog.PreFillProfile(profile);
|
||||
|
||||
var result = await dialog.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary && dialog.ResultProfile != null)
|
||||
{
|
||||
ViewModel.UpdateProfile(profile.Name, dialog.ResultProfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void DeleteProfile_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var menuItem = sender as MenuFlyoutItem;
|
||||
if (menuItem?.Tag is PowerDisplayProfile profile)
|
||||
{
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
var dialog = new ContentDialog
|
||||
{
|
||||
XamlRoot = this.XamlRoot,
|
||||
Title = resourceLoader.GetString("PowerDisplay_DeleteProfile_Title"),
|
||||
Content = string.Format(System.Globalization.CultureInfo.CurrentCulture, resourceLoader.GetString("PowerDisplay_DeleteProfile_Content"), profile.Name),
|
||||
PrimaryButtonText = resourceLoader.GetString("PowerDisplay_DeleteProfile_PrimaryButton"),
|
||||
CloseButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Cancel"),
|
||||
DefaultButton = ContentDialogButton.Close,
|
||||
};
|
||||
|
||||
var result = await dialog.ShowAsync();
|
||||
|
||||
if (result == ContentDialogResult.Primary)
|
||||
{
|
||||
ViewModel.DeleteProfile(profile.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateDefaultProfileName()
|
||||
{
|
||||
// Use shared ProfileHelper for consistent profile name generation
|
||||
var existingNames = ViewModel.Profiles.Select(p => p.Name).ToHashSet();
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
var baseName = resourceLoader.GetString("PowerDisplay_Profile_DefaultBaseName");
|
||||
return ProfileHelper.GenerateUniqueProfileName(existingNames, baseName);
|
||||
}
|
||||
|
||||
// Flag to prevent reentrant handling during programmatic checkbox changes
|
||||
private bool _isRestoringColorTempCheckbox;
|
||||
|
||||
private async void EnableColorTemperature_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Skip if we're programmatically restoring the checkbox state
|
||||
if (_isRestoringColorTempCheckbox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender is not CheckBox checkBox || checkBox.Tag is not MonitorInfo monitor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Only show warning when enabling (checking the box)
|
||||
if (checkBox.IsChecked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Show confirmation dialog with color temperature warning
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
var dialog = new ContentDialog
|
||||
{
|
||||
XamlRoot = this.XamlRoot,
|
||||
Title = resourceLoader.GetString("PowerDisplay_ColorTemperature_WarningTitle"),
|
||||
Content = new StackPanel
|
||||
{
|
||||
Spacing = 12,
|
||||
Children =
|
||||
{
|
||||
new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("PowerDisplay_ColorTemperature_WarningHeader"),
|
||||
FontWeight = Microsoft.UI.Text.FontWeights.Bold,
|
||||
Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["SystemFillColorCriticalBrush"],
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("PowerDisplay_ColorTemperature_WarningDescription"),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("PowerDisplay_ColorTemperature_WarningList"),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
Margin = new Thickness(20, 0, 0, 0),
|
||||
},
|
||||
new TextBlock
|
||||
{
|
||||
Text = resourceLoader.GetString("PowerDisplay_ColorTemperature_WarningConfirm"),
|
||||
FontWeight = Microsoft.UI.Text.FontWeights.SemiBold,
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
},
|
||||
},
|
||||
},
|
||||
PrimaryButtonText = resourceLoader.GetString("PowerDisplay_ColorTemperature_EnableButton"),
|
||||
CloseButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Cancel"),
|
||||
DefaultButton = ContentDialogButton.Close,
|
||||
};
|
||||
|
||||
var result = await dialog.ShowAsync();
|
||||
|
||||
if (result != ContentDialogResult.Primary)
|
||||
{
|
||||
// User cancelled: revert checkbox to unchecked
|
||||
_isRestoringColorTempCheckbox = true;
|
||||
try
|
||||
{
|
||||
checkBox.IsChecked = false;
|
||||
monitor.EnableColorTemperature = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isRestoringColorTempCheckbox = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<ContentDialog
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ProfileEditorDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tkcontrols="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:viewmodels="using:Microsoft.PowerToys.Settings.UI.ViewModels"
|
||||
Width="486"
|
||||
MinWidth="486"
|
||||
CloseButtonClick="ContentDialog_CloseButtonClick"
|
||||
DefaultButton="Primary"
|
||||
IsPrimaryButtonEnabled="{x:Bind ViewModel.CanSave, Mode=OneWay}"
|
||||
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid MinWidth="486">
|
||||
<Grid.Resources>
|
||||
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
||||
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
|
||||
<Thickness x:Key="SettingsExpanderItemPadding">0,8,0,8</Thickness>
|
||||
</Grid.Resources>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBox
|
||||
x:Name="ProfileNameTextBox"
|
||||
x:Uid="PowerDisplay_ProfileEditor_ProfileName"
|
||||
Margin="0,0,0,24"
|
||||
MaxLength="50"
|
||||
Text="{x:Bind ViewModel.ProfileName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<!-- Monitors List -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Spacing="16">
|
||||
<TextBlock x:Uid="PowerDisplay_ProfileEditor_Description" Style="{StaticResource BodyStrongTextBlockStyle}" />
|
||||
<ItemsControl ItemsSource="{x:Bind ViewModel.Monitors, Mode=OneWay}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="viewmodels:MonitorSelectionItem">
|
||||
<tkcontrols:SettingsExpander
|
||||
Margin="0,0,0,8"
|
||||
Description="{x:Bind Monitor.Id, Mode=OneWay}"
|
||||
Header="{x:Bind Monitor.DisplayName, Mode=OneWay}"
|
||||
IsExpanded="True">
|
||||
<tkcontrols:SettingsExpander.HeaderIcon>
|
||||
<FontIcon Glyph="{x:Bind Monitor.MonitorIconGlyph}" />
|
||||
</tkcontrols:SettingsExpander.HeaderIcon>
|
||||
<ToggleSwitch IsOn="{x:Bind IsSelected, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsExpander.Items>
|
||||
<tkcontrols:SettingsCard Padding="16,8,16,8" Visibility="{x:Bind Monitor.SupportsBrightness, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox IsChecked="{x:Bind IncludeBrightness, Mode=TwoWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_ProfileEditor_Brightness" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind Brightness, Mode=TwoWay}" />
|
||||
<tkcontrols:SettingsCard.Resources>
|
||||
<x:Double x:Key="SettingsCardLeftIndention">0</x:Double>
|
||||
</tkcontrols:SettingsCard.Resources>
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<tkcontrols:SettingsCard Padding="16,8,16,8" Visibility="{x:Bind Monitor.SupportsContrast, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox IsChecked="{x:Bind IncludeContrast, Mode=TwoWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_ProfileEditor_Contrast" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind Contrast, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard Padding="16,8,16,8" Visibility="{x:Bind Monitor.SupportsVolume, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox IsChecked="{x:Bind IncludeVolume, Mode=TwoWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_ProfileEditor_Volume" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<Slider
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="{x:Bind Volume, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<tkcontrols:SettingsCard Padding="16,8,16,8" Visibility="{x:Bind Monitor.SupportsColorTemperature, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<tkcontrols:SettingsCard.Header>
|
||||
<CheckBox IsChecked="{x:Bind IncludeColorTemperature, Mode=TwoWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<FontIcon FontSize="16" Glyph="" />
|
||||
<TextBlock x:Uid="PowerDisplay_ProfileEditor_ColorTemperature" VerticalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</CheckBox>
|
||||
</tkcontrols:SettingsCard.Header>
|
||||
<ComboBox
|
||||
x:Uid="PowerDisplay_ProfileEditor_ColorTemperature_ComboBox"
|
||||
MinWidth="{StaticResource SettingActionControlMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ItemsSource="{x:Bind Monitor.ColorPresetsForDisplay, Mode=OneWay}"
|
||||
SelectedValue="{x:Bind ColorTemperature, Mode=TwoWay}"
|
||||
SelectedValuePath="VcpValue" />
|
||||
</tkcontrols:SettingsCard>
|
||||
</tkcontrols:SettingsExpander.Items>
|
||||
</tkcontrols:SettingsExpander>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using PowerDisplay.Common.Models;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Dialog for creating/editing PowerDisplay profiles
|
||||
/// </summary>
|
||||
public sealed partial class ProfileEditorDialog : ContentDialog
|
||||
{
|
||||
public ProfileEditorViewModel ViewModel { get; private set; }
|
||||
|
||||
public PowerDisplayProfile? ResultProfile { get; private set; }
|
||||
|
||||
public ProfileEditorDialog(ObservableCollection<MonitorInfo> availableMonitors, string defaultName = "")
|
||||
{
|
||||
this.InitializeComponent();
|
||||
ViewModel = new ProfileEditorViewModel(availableMonitors, defaultName);
|
||||
|
||||
// Set localized strings for ContentDialog
|
||||
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||
Title = resourceLoader.GetString("PowerDisplay_ProfileEditor_Title");
|
||||
PrimaryButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Save");
|
||||
CloseButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Cancel");
|
||||
}
|
||||
|
||||
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
if (ViewModel.CanSave)
|
||||
{
|
||||
ResultProfile = ViewModel.CreateProfile();
|
||||
}
|
||||
}
|
||||
|
||||
private void ContentDialog_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
ResultProfile = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-fill the dialog with existing profile data
|
||||
/// </summary>
|
||||
public void PreFillProfile(PowerDisplayProfile profile)
|
||||
{
|
||||
if (profile == null || ViewModel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set profile name
|
||||
ViewModel.ProfileName = profile.Name;
|
||||
|
||||
// Pre-fill monitor settings from existing profile
|
||||
foreach (var monitorSetting in profile.MonitorSettings)
|
||||
{
|
||||
var monitorItem = ViewModel.Monitors.FirstOrDefault(m => m.Monitor.Id == monitorSetting.MonitorId);
|
||||
if (monitorItem != null)
|
||||
{
|
||||
monitorItem.IsSelected = true;
|
||||
|
||||
// Set brightness if included in profile
|
||||
if (monitorSetting.Brightness.HasValue)
|
||||
{
|
||||
monitorItem.IncludeBrightness = true;
|
||||
monitorItem.Brightness = monitorSetting.Brightness.Value;
|
||||
}
|
||||
|
||||
// Set color temperature if included in profile
|
||||
if (monitorSetting.ColorTemperatureVcp.HasValue)
|
||||
{
|
||||
monitorItem.IncludeColorTemperature = true;
|
||||
monitorItem.ColorTemperature = monitorSetting.ColorTemperatureVcp.Value;
|
||||
}
|
||||
|
||||
// Set contrast if included in profile
|
||||
if (monitorSetting.Contrast.HasValue)
|
||||
{
|
||||
monitorItem.IncludeContrast = true;
|
||||
monitorItem.Contrast = monitorSetting.Contrast.Value;
|
||||
}
|
||||
|
||||
// Set volume if included in profile
|
||||
if (monitorSetting.Volume.HasValue)
|
||||
{
|
||||
monitorItem.IncludeVolume = true;
|
||||
monitorItem.Volume = monitorSetting.Volume.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,6 +179,9 @@
|
||||
AutomationProperties.AutomationId="SystemToolsNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/SystemTools.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.InfoBadge>
|
||||
<InfoBadge Style="{StaticResource NewInfoBadge}" />
|
||||
</NavigationViewItem.InfoBadge>
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="AdvancedPasteNavigationItem"
|
||||
@@ -210,6 +213,16 @@
|
||||
helpers:NavHelper.NavigateTo="views:LightSwitchPage"
|
||||
AutomationProperties.AutomationId="LightSwitchNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/LightSwitch.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="PowerDisplayNavigationItem"
|
||||
x:Uid="Shell_PowerDisplay"
|
||||
helpers:NavHelper.NavigateTo="views:PowerDisplayPage"
|
||||
AutomationProperties.AutomationId="PowerDisplayNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/PowerDisplay.png}">
|
||||
<NavigationViewItem.InfoBadge>
|
||||
<InfoBadge Style="{StaticResource NewInfoBadge}" />
|
||||
</NavigationViewItem.InfoBadge>
|
||||
</NavigationViewItem>
|
||||
<NavigationViewItem
|
||||
x:Name="PowerLauncherNavigationItem"
|
||||
x:Uid="Shell_PowerLauncher"
|
||||
|
||||
Reference in New Issue
Block a user