// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #include "pch.h" #include "SettingContainer.h" #include "SettingContainer.g.cpp" #include "LibraryResources.h" using namespace winrt::Windows::UI::Xaml; namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { DependencyProperty SettingContainer::_HeaderProperty{ nullptr }; DependencyProperty SettingContainer::_HelpTextProperty{ nullptr }; DependencyProperty SettingContainer::_CurrentValueProperty{ nullptr }; DependencyProperty SettingContainer::_HasSettingValueProperty{ nullptr }; DependencyProperty SettingContainer::_SettingOverrideSourceProperty{ nullptr }; SettingContainer::SettingContainer() { _InitializeProperties(); } void SettingContainer::_InitializeProperties() { // Initialize any SettingContainer dependency properties here. // This performs a lazy load on these properties, instead of // initializing them when the DLL loads. if (!_HeaderProperty) { _HeaderProperty = DependencyProperty::Register( L"Header", xaml_typename(), xaml_typename(), PropertyMetadata{ nullptr }); } if (!_HelpTextProperty) { _HelpTextProperty = DependencyProperty::Register( L"HelpText", xaml_typename(), xaml_typename(), PropertyMetadata{ box_value(L"") }); } if (!_CurrentValueProperty) { _CurrentValueProperty = DependencyProperty::Register( L"CurrentValue", xaml_typename(), xaml_typename(), PropertyMetadata{ box_value(L"") }); } if (!_HasSettingValueProperty) { _HasSettingValueProperty = DependencyProperty::Register( L"HasSettingValue", xaml_typename(), xaml_typename(), PropertyMetadata{ box_value(false), PropertyChangedCallback{ &SettingContainer::_OnHasSettingValueChanged } }); } if (!_SettingOverrideSourceProperty) { _SettingOverrideSourceProperty = DependencyProperty::Register( L"SettingOverrideSource", xaml_typename(), xaml_typename(), PropertyMetadata{ nullptr, PropertyChangedCallback{ &SettingContainer::_OnHasSettingValueChanged } }); } } void SettingContainer::_OnHasSettingValueChanged(DependencyObject const& d, DependencyPropertyChangedEventArgs const& /*args*/) { // update visibility for override message and reset button const auto& obj{ d.try_as() }; get_self(obj)->_UpdateOverrideSystem(); } void SettingContainer::OnApplyTemplate() { if (const auto& child{ GetTemplateChild(L"ResetButton") }) { if (const auto& button{ child.try_as() }) { // Apply click handler for the reset button. // When clicked, we dispatch the bound ClearSettingValue event, // resulting in inheriting the setting value from the parent. button.Click([=](auto&&, auto&&) { _ClearSettingValueHandlers(*this, nullptr); // move the focus to the child control if (const auto& content{ Content() }) { if (const auto& control{ content.try_as() }) { control.Focus(FocusState::Programmatic); return; } else if (const auto& panel{ content.try_as() }) { for (const auto& panelChild : panel.Children()) { if (const auto& panelControl{ panelChild.try_as() }) { panelControl.Focus(FocusState::Programmatic); return; } } } // if we get here, we didn't find something to reasonably focus to. } }); // apply name (automation property) Automation::AutomationProperties::SetName(child, RS_(L"SettingContainer_OverrideMessageBaseLayer")); } } _UpdateOverrideSystem(); if (const auto& content{ Content() }) { if (const auto& obj{ content.try_as() }) { // apply header text as name (automation property) if (const auto& header{ Header() }) { const auto headerText{ header.try_as() }; if (headerText && !headerText->empty()) { Automation::AutomationProperties::SetName(obj, *headerText); } } // apply help text as tooltip and full description (automation property) const auto& helpText{ HelpText() }; if (!helpText.empty()) { Controls::ToolTipService::SetToolTip(obj, box_value(helpText)); Automation::AutomationProperties::SetFullDescription(obj, helpText); } } } } // Method Description: // - Updates the override system visibility and text // Arguments: // - void SettingContainer::_UpdateOverrideSystem() { if (const auto& child{ GetTemplateChild(L"ResetButton") }) { if (const auto& button{ child.try_as() }) { if (HasSettingValue()) { // We want to be smart about showing the override system. // Don't just show it if the user explicitly set the setting. // If the tooltip is empty, we'll hide the entire override system. const auto& settingSrc{ SettingOverrideSource() }; const auto tooltip{ _GenerateOverrideMessage(settingSrc) }; Controls::ToolTipService::SetToolTip(button, box_value(tooltip)); button.Visibility(tooltip.empty() ? Visibility::Collapsed : Visibility::Visible); } else { // a value is not being overridden; hide the override system button.Visibility(Visibility::Collapsed); } } } } // Method Description: // - Helper function for generating the override message // Arguments: // - profile: the profile that defines the setting (aka SettingOverrideSource) // Return Value: // - text specifying where the setting was defined. If empty, we don't want to show the system. hstring SettingContainer::_GenerateOverrideMessage(const IInspectable& settingOrigin) { // We only get here if the user had an override in place. Model::OriginTag originTag{ Model::OriginTag::None }; winrt::hstring source; if (const auto& profile{ settingOrigin.try_as() }) { source = profile.Source(); originTag = profile.Origin(); } else if (const auto& appearanceConfig{ settingOrigin.try_as() }) { const auto profile = appearanceConfig.SourceProfile(); source = profile.Source(); originTag = profile.Origin(); } if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled()) { // EXPERIMENTAL FEATURE // We will display arrows for all origins, and informative tooltips for Fragments and Generated if (originTag == Model::OriginTag::Fragment || originTag == Model::OriginTag::Generated) { // from a fragment extension or generated profile return hstring{ fmt::format(std::wstring_view{ RS_(L"SettingContainer_OverrideMessageFragmentExtension") }, source) }; } return RS_(L"SettingContainer_OverrideMessageBaseLayer"); } // STABLE FEATURE // We will only display arrows and informative tooltips for Fragments if (originTag == Model::OriginTag::Fragment) { // from a fragment extension return hstring{ fmt::format(std::wstring_view{ RS_(L"SettingContainer_OverrideMessageFragmentExtension") }, source) }; } return {}; // no tooltip } }