Fix navigation for profile.appearance settings (global profile too)

This commit is contained in:
Carlos Zamora 2025-11-17 15:41:19 -08:00
parent 45d75e701f
commit 81f881a579
6 changed files with 90 additions and 38 deletions

View File

@ -1134,6 +1134,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
INITIALIZE_BINDABLE_ENUM_SETTING(IntenseTextStyle, IntenseTextStyle, winrt::Microsoft::Terminal::Settings::Model::IntenseStyle, L"Appearance_IntenseTextStyle", L"Content");
}
void Appearances::BringIntoViewWhenLoaded(hstring elementToFocus)
{
if (elementToFocus.empty())
{
return;
}
_loadedRevoker = this->Loaded(winrt::auto_revoke, [weakThis{ get_weak() }, elementToFocus](auto&&, auto&&) {
if (const auto strongThis = weakThis.get())
{
if (const auto element = strongThis->FindName(elementToFocus))
{
element.as<FrameworkElement>().StartBringIntoView();
}
}
});
}
IObservableVector<Editor::Font> Appearances::FilteredFontList()
{
if (!_filteredFonts)

View File

@ -188,6 +188,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
struct Appearances : AppearancesT<Appearances>
{
Appearances();
void BringIntoViewWhenLoaded(hstring elementToFocus);
// CursorShape visibility logic
bool IsVintageCursor() const;
@ -210,6 +211,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
bool IsCustomFontWeight();
til::property_changed_event PropertyChanged;
winrt::Windows::UI::Xaml::FrameworkElement::Loaded_revoker _loadedRevoker;
WINRT_PROPERTY(Windows::Foundation::Collections::IObservableVector<Microsoft::Terminal::Settings::Editor::EnumEntry>, FontWeightList);

View File

@ -65,6 +65,25 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
return winrt::make<implementation::ProfileViewModel>(profile, appSettings, dispatcher);
}
static ProfileSubPage ProfileSubPageFromBreadcrumb(BreadcrumbSubPage subPage)
{
switch (subPage)
{
case BreadcrumbSubPage::None:
return ProfileSubPage::Base;
case BreadcrumbSubPage::Profile_Appearance:
return ProfileSubPage::Appearance;
case BreadcrumbSubPage::Profile_Terminal:
return ProfileSubPage::Terminal;
case BreadcrumbSubPage::Profile_Advanced:
return ProfileSubPage::Advanced;
default:
// This should never happen
assert(false);
return ProfileSubPage::Base;
}
}
Editor::FilteredSearchResult FilteredSearchResult::CreateNoResultsItem(const winrt::hstring& query)
{
return winrt::make<FilteredSearchResult>(nullptr, nullptr, hstring{ fmt::format(fmt::runtime(std::wstring{ RS_(L"Search_NoResults") }), query) });
@ -747,29 +766,36 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
else if (clickedItemTag == globalProfileTag)
{
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher()) };
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
profileVM.IsBaseLayer(true);
// lazy load profile defaults VM
if (!_profileDefaultsVM)
{
_profileDefaultsVM = _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher());
_profileDefaultsVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
_profileDefaultsVM.IsBaseLayer(true);
}
_SetupProfileEventHandling(profileVM);
_SetupProfileEventHandling(_profileDefaultsVM);
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(profileVM, *this, elementToFocus));
contentFrame().Navigate(xaml_typename<Editor::Profiles_Base>(), winrt::make<implementation::NavigateToProfileArgs>(_profileDefaultsVM, *this, elementToFocus));
const auto crumb = winrt::make<Breadcrumb>(box_value(clickedItemTag), RS_(L"Nav_ProfileDefaults/Content"), BreadcrumbSubPage::None);
_breadcrumbs.Append(crumb);
SettingsNav().SelectedItem(BaseLayerMenuItem());
// If we were given a label, make sure we are on the correct sub-page
if (subPage == BreadcrumbSubPage::Profile_Appearance)
// Pass along the element to focus to the ProfileViewModel.
// This will work as a staging area before we navigate to the correct sub-page
auto profileVMImpl = get_self<ProfileViewModel>(_profileDefaultsVM);
profileVMImpl->ElementToFocus(elementToFocus);
// Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
// event handler will do it
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
const bool needsForcedRefresh = _profileDefaultsVM.CurrentPage() == profileSubPage;
_profileDefaultsVM.CurrentPage(profileSubPage);
if (needsForcedRefresh)
{
profileVM.CurrentPage(ProfileSubPage::Appearance);
}
else if (subPage == BreadcrumbSubPage::Profile_Terminal)
{
profileVM.CurrentPage(ProfileSubPage::Terminal);
}
else if (subPage == BreadcrumbSubPage::Profile_Advanced)
{
profileVM.CurrentPage(ProfileSubPage::Advanced);
// If we're already on the correct sub-page, the PropertyChanged event won't fire.
// However, we still need to pass along the ElementToFocus, so we need to force a refresh.
profileVMImpl->ForceRefreshCurrentPage();
}
}
else if (clickedItemTag == colorSchemesTag)
@ -855,33 +881,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
auto profileVMImpl = get_self<ProfileViewModel>(profile);
profileVMImpl->ElementToFocus(elementToFocus);
// convert the BreadcrumbSubPage to ProfileSubPage
const ProfileSubPage profileSubPage = [&](BreadcrumbSubPage subPage) {
switch (subPage)
{
case BreadcrumbSubPage::None:
return ProfileSubPage::Base;
case BreadcrumbSubPage::Profile_Appearance:
return ProfileSubPage::Appearance;
case BreadcrumbSubPage::Profile_Terminal:
return ProfileSubPage::Terminal;
case BreadcrumbSubPage::Profile_Advanced:
return ProfileSubPage::Advanced;
default:
// This should never happen
assert(false);
}
}(subPage);
const bool needsForcedRefresh = profile.CurrentPage() == profileSubPage;
// Set the profile's 'CurrentPage' to the correct one, if this requires further navigation, the
// event handler will do it
const ProfileSubPage profileSubPage = ProfileSubPageFromBreadcrumb(subPage);
const bool needsForcedRefresh = profile.CurrentPage() == profileSubPage;
profile.CurrentPage(profileSubPage);
if (needsForcedRefresh)
{
// If we're already on the correct sub-page, the PropertyChanged event won't fire.
// However, we still need to pass along the ElementToFocus, so we need to force a refresh.
profileVMImpl->ForceRefreshCurrentPage();
profileVMImpl->ForceRefreshCurrentPage();
}
}

View File

@ -123,6 +123,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
til::generation_t _QuerySearchIndex(const hstring& queryText);
safe_void_coroutine _UpdateSearchIndex();
winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel _profileDefaultsVM{ nullptr };
Windows::Foundation::Collections::IVector<winrt::Microsoft::Terminal::Settings::Editor::ProfileViewModel> _profileVMs{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::ColorSchemesPageViewModel _colorSchemesPageVM{ nullptr };
winrt::Microsoft::Terminal::Settings::Editor::NewTabMenuViewModel _newTabMenuPageVM{ nullptr };

View File

@ -3,6 +3,7 @@
#include "pch.h"
#include "Profiles_Appearance.h"
#include "Appearances.h"
#include "ProfileViewModel.h"
#include "PreviewConnection.h"
@ -26,8 +27,17 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
_Profile = args.Profile();
_windowRoot = args.WindowRoot();
// TODO CARLOS: how to handle Appearances object
BringIntoViewWhenLoaded(args.ElementToFocus());
const auto elementToFocus = args.ElementToFocus();
if (elementToFocus.starts_with(L"App."))
{
// remove "App." prefix
std::wstring correctedName{ elementToFocus.c_str() };
get_self<implementation::Appearances>(DefaultAppearanceView())->BringIntoViewWhenLoaded(hstring{ correctedName.substr(4) });
}
else
{
BringIntoViewWhenLoaded(elementToFocus);
}
if (!_previewControl)
{

View File

@ -316,6 +316,13 @@ Get-ChildItem -Path $SourceDir -Recurse -Filter *.xaml | ForEach-Object {
$name = ""
}
# Profile.Appearance settings need a special prefix for the ElementName.
# This allows us to bring the element into view at runtime.
if ($filename -eq 'Appearances.xaml')
{
$name = 'App.' + $name
}
# Deduce NavigationParam
# duplicateForVM is used to duplicate the entry if we need a VM param at runtime (i.e. profile vs global profile)
$duplicateForVM = $false
@ -435,6 +442,11 @@ foreach ($e in $entries)
$e.ParentPage -match 'Profiles_Terminal' -or
$e.ParentPage -match 'Profiles_Advanced'))
{
# TODO CARLOS: needs special ElementToFocus (maybe I should be adding it earlier so that this works on Profiles.Defaults too)
# if ($e.File -eq 'Appearances.xaml')
# {
#
# }
$profileEntries += $formattedEntry
}
elseif ($e.SubPage -eq 'BreadcrumbSubPage::ColorSchemes_Edit')