terminal/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp
2021-11-09 14:38:31 -08:00

227 lines
9.3 KiB
C++

// 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<IInspectable>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ nullptr });
}
if (!_HelpTextProperty)
{
_HelpTextProperty =
DependencyProperty::Register(
L"HelpText",
xaml_typename<hstring>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ box_value(L"") });
}
if (!_CurrentValueProperty)
{
_CurrentValueProperty =
DependencyProperty::Register(
L"CurrentValue",
xaml_typename<hstring>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ box_value(L"") });
}
if (!_HasSettingValueProperty)
{
_HasSettingValueProperty =
DependencyProperty::Register(
L"HasSettingValue",
xaml_typename<bool>(),
xaml_typename<Editor::SettingContainer>(),
PropertyMetadata{ box_value(false), PropertyChangedCallback{ &SettingContainer::_OnHasSettingValueChanged } });
}
if (!_SettingOverrideSourceProperty)
{
_SettingOverrideSourceProperty =
DependencyProperty::Register(
L"SettingOverrideSource",
xaml_typename<IInspectable>(),
xaml_typename<Editor::SettingContainer>(),
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<Editor::SettingContainer>() };
get_self<SettingContainer>(obj)->_UpdateOverrideSystem();
}
void SettingContainer::OnApplyTemplate()
{
if (const auto& child{ GetTemplateChild(L"ResetButton") })
{
if (const auto& button{ child.try_as<Controls::Button>() })
{
// 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<Controls::Control>() })
{
control.Focus(FocusState::Programmatic);
return;
}
else if (const auto& panel{ content.try_as<Controls::Panel>() })
{
for (const auto& panelChild : panel.Children())
{
if (const auto& panelControl{ panelChild.try_as<Controls::Control>() })
{
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<DependencyObject>() })
{
// apply header text as name (automation property)
if (const auto& header{ Header() })
{
const auto headerText{ header.try_as<hstring>() };
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:
// - <none>
void SettingContainer::_UpdateOverrideSystem()
{
if (const auto& child{ GetTemplateChild(L"ResetButton") })
{
if (const auto& button{ child.try_as<Controls::Button>() })
{
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<Model::Profile>() })
{
source = profile.Source();
originTag = profile.Origin();
}
else if (const auto& appearanceConfig{ settingOrigin.try_as<Model::AppearanceConfig>() })
{
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
}
}