This pull request brings back the "Base Layer" page, now renamed to
"Defaults", and the "Reset to inherited value" buttons. The scope of
inheritance for which buttons will display has been widened.
The button will be visible in the following cases:
The user has set a setting for the current profile, and it overrides...
1. ... something in profiles.defaults.
2. ... something in a Fragment Extension profile.
3. ... something from a Dynamic Profile Generator.
4. ... something from the compiled-in defaults.
Compared to the original implementation of reset arrows, cases (1), (3)
and (4) are new. Rationale:
(1) The user can see a setting on the Defaults page, and they need a way
to reset back to it.
(3) Dynamic profiles are not meaningfully different from fragments, and
users may need a way to reset back to the default value generated
for WSL or PowerShell.
(4) The user can see a setting on the Defaults page, **BUT** they are
not the one who created it. They *still* need a way to get back to
it.
To support this, I've introduced another origin tag, "User", and renamed
"Custom" to "None". Due to the way origin/override detection works¹, we
cannot otherwise disambiguate between settings that came from the user
and settings that came from the compiled-in defaults.
Changes were required in TerminalSettings such that we could construct a
settings object with a profile that does not have a GUID. In making this
change, I fixed a bit of silliness where we took a profile, extracted
its guid, and used that guid to look up the same profile object. Oops.
I also fixed the PropertyChanged notifier to include the
XxxOverrideSource property.
The presence of the page and the reset arrows is restricted to
Preview- or Dev-branded builds. Stable builds will retain their current
behavior.
¹ `XxxOverrideSource` returns the profile *above* the current profile
that holds a value for setting `Xxx`. When the value is the
compiled-in value, `XxxOverrideSource` will be `null`. Since it's
supposed to be the profile above the current profile, it will also be
`null` if the profile contains a setting at this layer.
In short, `null` means "user specified" *or* "compiled in". Oops.
Fixes#10430
Validation
----------
* [x] Tested Release build to make sure it's mostly arrow-free (apart from fragments)
This pull request adds an appearance configuration object to our
settings model and app lib, allowing the control to be rendered
differently depending on its state, and then uses it to add support for
an "unfocused" appearance that the terminal will use when it's not in
focus.
To accomplish this, we isolated the appearance-related settings from
Profile (into AppearanceConfig) and TerminalSettings (into the
IControlAppearance and ICoreAppearance interfaces). A bunch of work was
done to make inheritance work.
The unfocused appearance inherits from the focused one _for that
profile_. This is important: If you define a
defaults.unfocusedAppearance, it will apply all of defaults' settings to
any leaf profile when a terminal in that profile is out of focus.
Specified in #8345Closes#3062Closes#2316
Removes base layer (aka profiles.defaults) from the Settings UI. `SettingContainer` was also updated to not present a revert arrow when overriding a base layer value.
The new experience is now as follows:
- The revert arrow will only appear if you are overriding a value from a fragment extension.
- Users are still able to fully interact with `profiles.defaults` in their settings.json. Doing so still propagates those changes to their profiles as normal. In this case, the Settings UI presents the base layer value as the one that you selected.
#6800 - Settings UI Epic
Closes#9539
This PR adds improved override message generation for inheritance in
SUI. The settings model now has an `OriginTag` to be able to denote
where a `Profile` came from. This tag is used in the `SettingContainer`
to generate a more specific override message.
## References
#6800 - SUI Epic
#8919 - SUI Inheritance PR
#8804 - SUI Inheritance (old issue)
## Detailed Description of the Pull Request / Additional comments
- **Terminal Settings Model**
- Introduced `PROJECTED_SETTING` as a macro to more easily declare the
functions for each setting
- Introduced `<setting>OverrideSource` which finds the `Profile` that
has \<setting\> defined
- Introduced `OriginTag Profile::Origin {Custom, InBox, Generated}` to
trace where a profile came from
- `DefaultProfileUtils` creates profiles for profile generators. So
that now sets the `Origin` tag to `Generated`
- `CascadiaSettings::LoadDefaults()` tags all profiles created as
`InBox`.
- The view model had to ingest the API change to be able to interact
with `<setting>OverrideSource`
- **Override Message Generation**
- The reset button now has a more specific tooltip
- The reset button now only appears if base layer is being overridden
- We use the settings model changes to determine the message to
display for the target
## Validation Steps Performed
Tested the following cases:
- overrides nothing (inherited setting)
- overrides value inherited from...
- base layer
- a profile generator
- in-box profile
- global settings should not have this feature
## Summary of the Pull Request
Introduces the `SettingContainer`. `SettingContainer` is used to wrap a setting in the settings UI and provide the following functionality:
- a reset button next to the header
- tooltips and automation properties for the setting being wrapped
- a comment stating if you are currently overriding a setting
## References
[Spec - Inheritance in Settings UI](https://github.com/microsoft/terminal/blob/main/doc/specs/%231564%20-%20Settings%20UI/cascading-settings.md)
#8804 - removes the ambiguity of leaving a setting blank
#6800 - Settings UI Epic
#8899 - Automation properties for Settings UI
#8768 - Keyboard Navigation
## PR Checklist
* [X] Closes#8804
## Detailed Description of the Pull Request / Additional comments
A few highlights in this PR:
- CommonResources.xaml:
- we need to merge the SettingContainerStyle.xaml in there. Otherwise, XAML doesn't merge these files properly and can't apply the template.
- Profiles.cpp:
- view model checks if the starting directory and background image were reset, to determine which value to show when unchecking the special value
- `Profiles::OnNavigatedTo()` needs a property changed handler to update its own "Current<Setting>" and update the UI properly
- Profiles.xaml:
- basically wrapped all of the settings we want to be inheritable in there
- `Binding` is used instead of `x:Bind` in some places because `x:Bind` can't find the parent `SettingContainer` and gives you a compiler error.
- Resources.resw:
- had to set the "HeaderText" and "HelpText" on each setting container. Does a decent localization burden, unfortunately.
- `SettingContainer` files
- This operates by creating a template and applying that template over other settings. This allows you to inject the existing controls inside of this. This means that we need to provide our UIElements names and access/modify them via `OnApplyTemplate`
- We had to remove the header from each individual control, and have `SettingContainer` be in charge of it. This allows us to add the reset button in there.
- Due to the problem mentioned earlier about CommonResources.xaml, we can't reference anything from CommonResources.xaml.
- Using `DependencyProperty` to let us set a few properties in the XML files. Particularly, `Has<Setting>` and `Clear<Setting>` are what do all the heavy lifting of interacting with the inheritance model.
## Demo
![Inheritance Demo](https://user-images.githubusercontent.com/11050425/106192086-92a56680-6160-11eb-838c-4ec0beb54965.gif)
## Validation Steps Performed
- Verified correct binding behavior with the following generic setting controls:
- radio buttons
- toggle switch
- text block
- slider
- settings with browse buttons
- the background image alignment control
- controls with special check boxes (starting directory and background image)
## Next Steps
- The automation properties have been verified using NVDA. This is a part of resolving #8899.
- The override text is currently "Overrides a setting". According to #8269, we actually want to add a hyperlink in there that navigates to the parent profile object. This will be a follow-up task as it requires settings model changes.