diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.cpp b/src/cascadia/TerminalSettingsEditor/MainPage.cpp index 69d52294ed8..1cc9c706550 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.cpp +++ b/src/cascadia/TerminalSettingsEditor/MainPage.cpp @@ -33,6 +33,7 @@ static const std::wstring_view launchTag{ L"Launch_Nav" }; static const std::wstring_view interactionTag{ L"Interaction_Nav" }; static const std::wstring_view renderingTag{ L"Rendering_Nav" }; static const std::wstring_view actionsTag{ L"Actions_Nav" }; +static const std::wstring_view globalProfileTag{ L"GlobalProfile_Nav" }; static const std::wstring_view addProfileTag{ L"AddProfile" }; static const std::wstring_view colorSchemesTag{ L"ColorSchemes_Nav" }; static const std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" }; @@ -295,6 +296,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { contentFrame().Navigate(xaml_typename(), winrt::make(_settingsClone)); } + else if (clickedItemTag == globalProfileTag) + { + auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) }; + profileVM.IsBaseLayer(true); + _lastProfilesNavState = winrt::make(profileVM, + _settingsClone.GlobalSettings().ColorSchemes(), + _lastProfilesNavState, + *this); + + contentFrame().Navigate(xaml_typename(), _lastProfilesNavState); + } else if (clickedItemTag == colorSchemesTag) { contentFrame().Navigate(xaml_typename(), _colorSchemesNavState); @@ -456,4 +468,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation SettingsNav().SelectedItem(newSelectedItem); _Navigate(newSelectedItem.try_as().Tag().try_as()); } + + bool MainPage::ShowBaseLayerMenuItem() const noexcept + { + return Feature_ShowProfileDefaultsInSettings::IsEnabled(); + } } diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.h b/src/cascadia/TerminalSettingsEditor/MainPage.h index 401c2576eb0..24c2c9cd503 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.h +++ b/src/cascadia/TerminalSettingsEditor/MainPage.h @@ -26,6 +26,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation bool TryPropagateHostingWindow(IInspectable object) noexcept; uint64_t GetHostingWindow() const noexcept; + bool ShowBaseLayerMenuItem() const noexcept; + TYPED_EVENT(OpenJson, Windows::Foundation::IInspectable, Model::SettingsTarget); private: diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.idl b/src/cascadia/TerminalSettingsEditor/MainPage.idl index 2513c8b7b40..6c368713a73 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.idl +++ b/src/cascadia/TerminalSettingsEditor/MainPage.idl @@ -23,5 +23,7 @@ namespace Microsoft.Terminal.Settings.Editor // Due to the aforementioned bug, we can't use IInitializeWithWindow _here_ either. // Let's just smuggle the HWND in as a UInt64 :| void SetHostingWindow(UInt64 window); + + Boolean ShowBaseLayerMenuItem { get; }; } } diff --git a/src/cascadia/TerminalSettingsEditor/MainPage.xaml b/src/cascadia/TerminalSettingsEditor/MainPage.xaml index 35c801e5125..76e7c733d12 100644 --- a/src/cascadia/TerminalSettingsEditor/MainPage.xaml +++ b/src/cascadia/TerminalSettingsEditor/MainPage.xaml @@ -88,6 +88,15 @@ + + + + + + diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.cpp b/src/cascadia/TerminalSettingsEditor/Profiles.cpp index 15838cb3e36..d1604ec7430 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.cpp +++ b/src/cascadia/TerminalSettingsEditor/Profiles.cpp @@ -152,7 +152,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation Model::TerminalSettings ProfileViewModel::TermSettings() const { - return Model::TerminalSettings::CreateWithProfileByID(_appSettings, _profile.Guid(), nullptr).DefaultSettings(); + return Model::TerminalSettings::CreateWithProfile(_appSettings, _profile, nullptr).DefaultSettings(); } // Method Description: diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw index 86bfd3e5533..467dc069db2 100644 --- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw +++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw @@ -452,8 +452,8 @@ Header for a menu item. This opens the JSON file that is used to log the app's settings. - Base layer - Header for the "base layer" menu item. This navigates to a page that lets you see and modify settings that affect profiles. The base layer is the lowest layer of profile settings that all other profile settings are based on. If a profile doesn't define a setting, base layer is responsible for figuring out what that setting is supposed to be. + Defaults + Header for the "defaults" menu item. This navigates to a page that lets you see and modify settings that affect profiles. This is the lowest layer of profile settings that all other profile settings are based on. If a profile doesn't define a setting, this page is responsible for figuring out what that setting is supposed to be. Rendering @@ -1012,7 +1012,7 @@ Settings defined here will apply to all profiles unless they are overridden by a profile's settings. - A disclaimer presented at the top of a page. See "Nav_ProfileDefaults.Content" for a description on what the base layer does in the app. + A disclaimer presented at the top of a page. See "Nav_ProfileDefaults.Content" for a description on what the defaults layer does in the app. Yes, delete profile @@ -1087,8 +1087,8 @@ Header for a control to toggle animations on panes. "Enabled" value enables the animations. - Reset to base layer value. - "base layer" should match Nav_ProfileDefaults.Content's text. This is a text label on a button. + Reset to inherited value. + This button will remove a user's customization from a given setting, restoring it to the value that the profile inherited. This is a text label on a button. Terminal colors diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp b/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp index f2566da7f84..7d53785c608 100644 --- a/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp +++ b/src/cascadia/TerminalSettingsEditor/SettingContainer.cpp @@ -57,9 +57,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation _SettingOverrideSourceProperty = DependencyProperty::Register( L"SettingOverrideSource", - xaml_typename(), + xaml_typename(), xaml_typename(), - PropertyMetadata{ nullptr }); + PropertyMetadata{ nullptr, PropertyChangedCallback{ &SettingContainer::_OnHasSettingValueChanged } }); } } @@ -152,17 +152,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation // 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. - hstring tooltip{}; const auto& settingSrc{ SettingOverrideSource() }; - if (const auto& profile{ settingSrc.try_as() }) - { - tooltip = _GenerateOverrideMessage(profile); - } - else if (const auto& appearanceConfig{ settingSrc.try_as() }) - { - tooltip = _GenerateOverrideMessage(appearanceConfig.SourceProfile()); - } + const auto tooltip{ _GenerateOverrideMessage(settingSrc) }; Controls::ToolTipService::SetToolTip(button, box_value(tooltip)); button.Visibility(tooltip.empty() ? Visibility::Collapsed : Visibility::Visible); @@ -182,35 +174,43 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation // - 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 Model::Profile& profile) + hstring SettingContainer::_GenerateOverrideMessage(const IInspectable& settingOrigin) { - const auto originTag{ profile.Origin() }; - if (originTag == Model::OriginTag::InBox) + // 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() }) { - // in-box profile - return {}; + source = profile.Source(); + originTag = profile.Origin(); } - else if (originTag == Model::OriginTag::Generated) + else if (const auto& appearanceConfig{ settingOrigin.try_as() }) { - // from a dynamic profile generator - return {}; + const auto profile = appearanceConfig.SourceProfile(); + source = profile.Source(); + originTag = profile.Origin(); } - else if (originTag == Model::OriginTag::Fragment) + + if constexpr (Feature_ShowProfileDefaultsInSettings::IsEnabled()) { - // from a fragment extension - return hstring{ fmt::format(std::wstring_view{ RS_(L"SettingContainer_OverrideMessageFragmentExtension") }, profile.Source()) }; + // 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"); } - else + + // STABLE FEATURE + // We will only display arrows and informative tooltips for Fragments + if (originTag == Model::OriginTag::Fragment) { - // base layer - // TODO GH#3818: When we add profile inheritance as a setting, - // we'll need an extra conditional check to see if this - // is the base layer or some other profile - - // GH#9539: Base Layer has been removed from the Settings UI. - // In the event that the Base Layer comes back, - // return RS_(L"SettingContainer_OverrideMessageBaseLayer") instead - return {}; + // from a fragment extension + return hstring{ fmt::format(std::wstring_view{ RS_(L"SettingContainer_OverrideMessageFragmentExtension") }, source) }; } + return {}; // no tooltip } } diff --git a/src/cascadia/TerminalSettingsEditor/SettingContainer.h b/src/cascadia/TerminalSettingsEditor/SettingContainer.h index 490792c99d9..de9570e7f11 100644 --- a/src/cascadia/TerminalSettingsEditor/SettingContainer.h +++ b/src/cascadia/TerminalSettingsEditor/SettingContainer.h @@ -38,7 +38,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation private: static void _InitializeProperties(); static void _OnHasSettingValueChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e); - static hstring _GenerateOverrideMessage(const Model::Profile& profile); + static hstring _GenerateOverrideMessage(const IInspectable& settingOrigin); void _UpdateOverrideSystem(); }; } diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp index 3b4aa1db639..398fe1ccc5e 100644 --- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp +++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp @@ -850,6 +850,7 @@ void CascadiaSettings::LayerJson(const Json::Value& json) void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson) { // Layer the json on top of an existing profile, if we have one: + winrt::com_ptr profile{ nullptr }; auto profileIndex{ _FindMatchingProfileIndex(profileJson) }; if (profileIndex) { @@ -862,6 +863,7 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson) // When we loaded Profile.Defaults, we created an empty child already. // So this just populates the empty child parent->LayerJson(profileJson); + profile.copy_from(parent); } else { @@ -871,6 +873,7 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson) // replace parent in _profiles with child _allProfiles.SetAt(*profileIndex, *childImpl); + profile = std::move(childImpl); } } else @@ -880,7 +883,7 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson) // `source`. Dynamic profiles _must_ be layered on an existing profile. if (!Profile::IsDynamicProfileObject(profileJson)) { - auto profile{ winrt::make_self() }; + profile = winrt::make_self(); // GH#2325: If we have a set of default profile settings, set that as my parent. // We _won't_ have these settings yet for defaults, dynamic profiles. @@ -893,6 +896,12 @@ void CascadiaSettings::_LayerOrCreateProfile(const Json::Value& profileJson) _allProfiles.Append(*profile); } } + + if (profile && _userDefaultProfileSettings) + { + // If we've loaded defaults{} we're in the "user settings" phase for sure + profile->Origin(OriginTag::User); + } } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h index d61c35308c4..365775586cc 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -103,7 +103,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation void _FinalizeInheritance() override; - WINRT_PROPERTY(OriginTag, Origin, OriginTag::Custom); + WINRT_PROPERTY(OriginTag, Origin, OriginTag::None); INHERITABLE_SETTING(Model::Profile, guid, Guid, _GenerateGuidForProfile(Name(), Source())); INHERITABLE_SETTING(Model::Profile, hstring, Name, L"Default"); diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index 3015c5119d2..92a671dbf94 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -14,7 +14,8 @@ namespace Microsoft.Terminal.Settings.Model // This tag is used to identify the context in which the Profile was created enum OriginTag { - Custom = 0, + None = 0, + User, InBox, Generated, Fragment, diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp index de0047be2f3..a0ec41a43ad 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp @@ -62,14 +62,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation // Return Value: // - A TerminalSettingsCreateResult, which contains a pair of TerminalSettings objects, // one for when the terminal is focused and the other for when the terminal is unfocused - Model::TerminalSettingsCreateResult TerminalSettings::CreateWithProfileByID(const Model::CascadiaSettings& appSettings, winrt::guid profileGuid, const IKeyBindings& keybindings) + Model::TerminalSettingsCreateResult TerminalSettings::CreateWithProfile(const Model::CascadiaSettings& appSettings, const Model::Profile& profile, const IKeyBindings& keybindings) { auto settings{ winrt::make_self() }; settings->_KeyBindings = keybindings; - const auto profile = appSettings.FindProfile(profileGuid); - THROW_HR_IF_NULL(E_INVALIDARG, profile); - const auto globals = appSettings.GlobalSettings(); settings->_ApplyProfileSettings(profile); settings->_ApplyGlobalSettings(globals); @@ -86,6 +83,25 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation return winrt::make(*settings, child); } + // Method Description: + // - Create a TerminalSettingsCreateResult for the provided profile guid. We'll + // use the guid to look up the profile that should be used to + // create these TerminalSettings. Then, we'll apply settings contained in the + // global and profile settings to the instance. + // Arguments: + // - appSettings: the set of settings being used to construct the new terminal + // - profileGuid: the unique identifier (guid) of the profile + // - keybindings: the keybinding handler + // Return Value: + // - A TerminalSettingsCreateResult, which contains a pair of TerminalSettings objects, + // one for when the terminal is focused and the other for when the terminal is unfocused + Model::TerminalSettingsCreateResult TerminalSettings::CreateWithProfileByID(const Model::CascadiaSettings& appSettings, winrt::guid profileGuid, const IKeyBindings& keybindings) + { + const auto profile = appSettings.FindProfile(profileGuid); + THROW_HR_IF_NULL(E_INVALIDARG, profile); + return CreateWithProfile(appSettings, profile, keybindings); + } + // Method Description: // - Create a TerminalSettings object for the provided newTerminalArgs. We'll // use the newTerminalArgs to look up the profile that should be used to diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 4f8a850009d..5e87d415143 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -53,6 +53,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation { TerminalSettings() = default; + static Model::TerminalSettingsCreateResult CreateWithProfile(const Model::CascadiaSettings& appSettings, + const Model::Profile& profile, + const Control::IKeyBindings& keybindings); + static Model::TerminalSettingsCreateResult CreateWithProfileByID(const Model::CascadiaSettings& appSettings, guid profileGuid, const Control::IKeyBindings& keybindings); diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl index 73661d096ce..a28c6ab81a8 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.idl +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.idl @@ -26,6 +26,7 @@ namespace Microsoft.Terminal.Settings.Model { TerminalSettings(); + static TerminalSettingsCreateResult CreateWithProfile(CascadiaSettings appSettings, Profile profile, Microsoft.Terminal.Control.IKeyBindings keybindings); static TerminalSettingsCreateResult CreateWithProfileByID(CascadiaSettings appSettings, Guid profileGuid, Microsoft.Terminal.Control.IKeyBindings keybindings); static TerminalSettingsCreateResult CreateWithNewTerminalArgs(CascadiaSettings appSettings, NewTerminalArgs newTerminalArgs, Microsoft.Terminal.Control.IKeyBindings keybindings); static TerminalSettingsCreateResult CreateWithParent(TerminalSettingsCreateResult parent); diff --git a/src/features.xml b/src/features.xml index 7ad1db40c0c..4eb0f6aaaa4 100644 --- a/src/features.xml +++ b/src/features.xml @@ -49,4 +49,13 @@ WindowsInbox + + + Feature_ShowProfileDefaultsInSettings + Whether to show the "defaults" page in the Terminal settings UI + 10430 + AlwaysEnabled + + +