Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Profile.BellSound to Settings UI #17983

Merged
merged 17 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/spelling/allow/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dzhe
Emacspeak
Fitt
FTCS
flac
gantt
gfm
ghe
Expand Down
11 changes: 11 additions & 0 deletions src/cascadia/TerminalSettingsEditor/CommonResources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@
<Setter Property="TextWrapping" Value="Wrap" />
</Style>

<!-- Text Block -->
<Style x:Key="TextBlockSettingStyle"
BasedOn="{StaticResource BaseTextBlockStyle}"
TargetType="TextBlock">
<Setter Property="MinWidth" Value="{StaticResource StandardBoxMinWidth}" />
<Setter Property="MaxWidth" Value="400" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>

<Style x:Key="TextBlockSubHeaderStyle"
BasedOn="{StaticResource SubtitleTextBlockStyle}"
TargetType="TextBlock">
Expand Down
12 changes: 6 additions & 6 deletions src/cascadia/TerminalSettingsEditor/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ static const std::wstring_view globalAppearanceTag{ L"GlobalAppearance_Nav" };

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
static Editor::ProfileViewModel _viewModelForProfile(const Model::Profile& profile, const Model::CascadiaSettings& appSettings)
static Editor::ProfileViewModel _viewModelForProfile(const Model::Profile& profile, const Model::CascadiaSettings& appSettings, const Windows::UI::Core::CoreDispatcher& dispatcher)
{
return winrt::make<implementation::ProfileViewModel>(profile, appSettings);
return winrt::make<implementation::ProfileViewModel>(profile, appSettings, dispatcher);
}

MainPage::MainPage(const CascadiaSettings& settings) :
Expand Down Expand Up @@ -386,7 +386,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
else if (currentPage == ProfileSubPage::Advanced)
{
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), profile);
contentFrame().Navigate(xaml_typename<Editor::Profiles_Advanced>(), winrt::make<implementation::NavigateToProfileArgs>(profile, *this));
const auto crumb = winrt::make<Breadcrumb>(breadcrumbTag, RS_(L"Profile_Advanced/Header"), BreadcrumbSubPage::Profile_Advanced);
_breadcrumbs.Append(crumb);
SettingsMainPage_ScrollViewer().ScrollToVerticalOffset(0);
Expand Down Expand Up @@ -447,7 +447,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
}
else if (clickedItemTag == globalProfileTag)
{
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone) };
auto profileVM{ _viewModelForProfile(_settingsClone.ProfileDefaults(), _settingsClone, Dispatcher()) };
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
profileVM.IsBaseLayer(true);

Expand Down Expand Up @@ -649,7 +649,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
if (!profile.Deleted())
{
auto profileVM = _viewModelForProfile(profile, _settingsClone);
auto profileVM = _viewModelForProfile(profile, _settingsClone, Dispatcher());
profileVM.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
auto navItem = _CreateProfileNavViewItem(profileVM);
_menuItemSource.Append(navItem);
Expand Down Expand Up @@ -705,7 +705,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void MainPage::_CreateAndNavigateToNewProfile(const uint32_t index, const Model::Profile& profile)
{
const auto newProfile{ profile ? profile : _settingsClone.CreateNewProfile() };
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone) };
const auto profileViewModel{ _viewModelForProfile(newProfile, _settingsClone, Dispatcher()) };
profileViewModel.SetupAppearances(_colorSchemesPageVM.AllColorSchemes());
const auto navItem{ _CreateProfileNavViewItem(profileViewModel) };

Expand Down
183 changes: 180 additions & 3 deletions src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

static constexpr std::wstring_view HideIconValue{ L"none" };

ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings) :
ProfileViewModel::ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& appSettings, const Windows::UI::Core::CoreDispatcher& dispatcher) :
_profile{ profile },
_defaultAppearanceViewModel{ winrt::make<implementation::AppearanceViewModel>(profile.DefaultAppearance().try_as<AppearanceConfig>()) },
_originalProfileGuid{ profile.Guid() },
_appSettings{ appSettings },
_unfocusedAppearanceViewModel{ nullptr }
_unfocusedAppearanceViewModel{ nullptr },
_dispatcher{ dispatcher }
{
INITIALIZE_BINDABLE_ENUM_SETTING(AntiAliasingMode, TextAntialiasingMode, winrt::Microsoft::Terminal::Control::TextAntialiasingMode, L"Profile_AntialiasingMode", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING_REVERSE_ORDER(CloseOnExitMode, CloseOnExitMode, winrt::Microsoft::Terminal::Settings::Model::CloseOnExitMode, L"Profile_CloseOnExit", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(ScrollState, ScrollbarState, winrt::Microsoft::Terminal::Control::ScrollbarState, L"Profile_ScrollbarVisibility", L"Content");
INITIALIZE_BINDABLE_ENUM_SETTING(PathTranslationStyle, PathTranslationStyle, winrt::Microsoft::Terminal::Control::PathTranslationStyle, L"Profile_PathTranslationStyle", L"Content");

_InitializeCurrentBellSounds();

// set up IconTypes
std::vector<IInspectable> iconTypes;
iconTypes.reserve(4);
Expand Down Expand Up @@ -112,6 +115,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
Icon(CurrentEmojiIcon());
}
else if (viewModelProperty == L"CurrentBellSounds")
{
// we already have infrastructure in place to
// propagate changes from the CurrentBellSounds
// to the model. Refer to...
// - _InitializeCurrentBellSounds() --> _CurrentBellSounds.VectorChanged()
// - RequestAddBellSound()
// - RequestDeleteBellSound()
_MarkDuplicateBellSoundDirectories();
_NotifyChanges(L"BellSoundPreview", L"HasBellSound");
}
else if (viewModelProperty == L"BellSound")
{
_InitializeCurrentBellSounds();
}
else if (viewModelProperty == L"PathTranslationStyle")
{
_NotifyChanges(L"CurrentPathTranslationStyle");
Expand Down Expand Up @@ -696,9 +714,168 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
BellStyle(currentStyle);
}

// Method Description:
// - Construct _CurrentBellSounds by importing the _inherited_ value from the model
// - Adds a PropertyChanged handler to each BellSoundViewModel to propagate changes to the model
void ProfileViewModel::_InitializeCurrentBellSounds()
{
_CurrentBellSounds = winrt::single_threaded_observable_vector<Editor::BellSoundViewModel>();
if (const auto soundList = _profile.BellSound())
{
for (const auto&& bellSound : soundList)
{
_CurrentBellSounds.Append(winrt::make<BellSoundViewModel>(bellSound));
}
}
_MarkDuplicateBellSoundDirectories();
_CheckBellSoundsExistence();
_NotifyChanges(L"CurrentBellSounds");
}

// Method Description:
// - If the current layer is inheriting the bell sound from its parent,
// we need to copy the _inherited_ bell sound list to the current layer
// so that we can then apply modifications to it
void ProfileViewModel::_PrepareModelForBellSoundModification()
{
if (!_profile.HasBellSound())
{
std::vector<hstring> newSounds;
if (const auto inheritedSounds = _profile.BellSound())
DHowett marked this conversation as resolved.
Show resolved Hide resolved
{
// copy inherited bell sounds to the current layer
newSounds.reserve(inheritedSounds.Size());
for (const auto sound : inheritedSounds)
{
newSounds.push_back(sound);
}
}
// if we didn't inherit any bell sounds,
// we should still set the bell sound to an empty list (instead of null)
_profile.BellSound(winrt::single_threaded_vector<hstring>(std::move(newSounds)));
}
}

// Method Description:
// - Check if any bell sounds share the same name.
// If they do, mark them so that they show the directory path in the UI
void ProfileViewModel::_MarkDuplicateBellSoundDirectories()
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
{
for (uint32_t i = 0; i < _CurrentBellSounds.Size(); i++)
{
auto soundA = _CurrentBellSounds.GetAt(i);
for (uint32_t j = i + 1; j < _CurrentBellSounds.Size(); j++)
{
auto soundB = _CurrentBellSounds.GetAt(j);
if (soundA.DisplayPath() == soundB.DisplayPath())
{
get_self<BellSoundViewModel>(soundA)->ShowDirectory(true);
get_self<BellSoundViewModel>(soundB)->ShowDirectory(true);
}
}
}
}

// Method Description:
// - Check if the bell sounds exist on disk. Mark any that don't exist
// so that they show the appropriate UI
safe_void_coroutine ProfileViewModel::_CheckBellSoundsExistence()
{
co_await winrt::resume_background();
std::vector<Editor::BellSoundViewModel> markedSounds;
for (auto&& sound : _CurrentBellSounds)
{
if (!std::filesystem::exists(std::wstring_view{ sound.Path() }))
{
markedSounds.push_back(sound);
}
}

co_await winrt::resume_foreground(_dispatcher);
for (auto&& sound : markedSounds)
{
get_self<BellSoundViewModel>(sound)->FileExists(false);
}
}

BellSoundViewModel::BellSoundViewModel(hstring path) :
_Path{ path }
{
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
if (args.PropertyName() == L"FileExists")
{
_NotifyChanges(L"DisplayPath", L"SubText");
}
});
}

hstring BellSoundViewModel::DisplayPath() const
{
if (_FileExists)
{
// filename
const std::filesystem::path filePath{ std::wstring_view{ _Path } };
return hstring{ filePath.filename().wstring() };
}
return _Path;
}

hstring BellSoundViewModel::SubText() const
{
if (_FileExists)
{
// Directory
const std::filesystem::path filePath{ std::wstring_view{ _Path } };
return hstring{ filePath.parent_path().wstring() };
}
return RS_(L"Profile_BellSoundNotFound");
}

hstring ProfileViewModel::BellSoundPreview()
{
const auto& currentSound = BellSound();
if (!currentSound || currentSound.Size() == 0)
{
return RS_(L"Profile_BellSoundPreviewDefault");
}
else if (currentSound.Size() == 1)
{
std::filesystem::path filePath{ std::wstring_view{ currentSound.GetAt(0) } };
return hstring{ filePath.filename().wstring() };
}
return RS_(L"Profile_BellSoundPreviewMultiple");
}

void ProfileViewModel::RequestAddBellSound(hstring path)
{
// If we were inheriting our bell sound,
// copy it over to the current layer and apply modifications
_PrepareModelForBellSoundModification();

// No need to check if the file exists. We came from the FilePicker. That's good enough.
_CurrentBellSounds.Append(winrt::make<BellSoundViewModel>(path));
_profile.BellSound().Append(path);
_NotifyChanges(L"CurrentBellSounds");
}

void ProfileViewModel::RequestDeleteBellSound(const Editor::BellSoundViewModel& vm)
{
uint32_t index;
if (_CurrentBellSounds.IndexOf(vm, index))
{
// If we were inheriting our bell sound,
// copy it over to the current layer and apply modifications
_PrepareModelForBellSoundModification();
DHowett marked this conversation as resolved.
Show resolved Hide resolved

_CurrentBellSounds.RemoveAt(index);
_profile.BellSound().RemoveAt(index);
_NotifyChanges(L"CurrentBellSounds");
}
}

void ProfileViewModel::DeleteProfile()
{
auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(Guid()) };
const auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(Guid()) };
DeleteProfileRequested.raise(*this, *deleteProfileArgs);
}

Expand Down
26 changes: 25 additions & 1 deletion src/cascadia/TerminalSettingsEditor/ProfileViewModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "DeleteProfileEventArgs.g.h"
#include "NavigateToProfileArgs.g.h"
#include "BellSoundViewModel.g.h"
#include "ProfileViewModel.g.h"
#include "Utils.h"
#include "ViewModelHelpers.h"
Expand All @@ -26,6 +27,18 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Editor::ProfileViewModel _Profile{ nullptr };
};

struct BellSoundViewModel : BellSoundViewModelT<BellSoundViewModel>, ViewModelHelper<BellSoundViewModel>
{
public:
BellSoundViewModel(hstring path);

hstring DisplayPath() const;
hstring SubText() const;
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, FileExists, true);
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, Path);
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, ShowDirectory);
};

struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
Expand All @@ -35,7 +48,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
static Windows::Foundation::Collections::IObservableVector<Editor::Font> MonospaceFontList() noexcept { return _MonospaceFontList; };
static Windows::Foundation::Collections::IVector<IInspectable> BuiltInIcons() noexcept { return _BuiltInIcons; };

ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings);
ProfileViewModel(const Model::Profile& profile, const Model::CascadiaSettings& settings, const Windows::UI::Core::CoreDispatcher& dispatcher);
Model::TerminalSettings TermSettings() const;
void DeleteProfile();

Expand All @@ -47,6 +60,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void SetBellStyleWindow(winrt::Windows::Foundation::IReference<bool> on);
void SetBellStyleTaskbar(winrt::Windows::Foundation::IReference<bool> on);

hstring BellSoundPreview();
void RequestAddBellSound(hstring path);
void RequestDeleteBellSound(const Editor::BellSoundViewModel& vm);

void SetAcrylicOpacityPercentageValue(double value)
{
Opacity(static_cast<float>(value) / 100.0f);
Expand Down Expand Up @@ -102,6 +119,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
til::typed_event<Editor::ProfileViewModel, Editor::DeleteProfileEventArgs> DeleteProfileRequested;

VIEW_MODEL_OBSERVABLE_PROPERTY(ProfileSubPage, CurrentPage);
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::Collections::IObservableVector<Editor::BellSoundViewModel>, CurrentBellSounds);
VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::IInspectable, CurrentBuiltInIcon);
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, CurrentEmojiIcon);

Expand All @@ -126,6 +144,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
OBSERVABLE_PROJECTED_SETTING(_profile, SnapOnInput);
OBSERVABLE_PROJECTED_SETTING(_profile, AltGrAliasing);
OBSERVABLE_PROJECTED_SETTING(_profile, BellStyle);
OBSERVABLE_PROJECTED_SETTING(_profile, BellSound);
OBSERVABLE_PROJECTED_SETTING(_profile, Elevate);
OBSERVABLE_PROJECTED_SETTING(_profile, ReloadEnvironmentVariables);
OBSERVABLE_PROJECTED_SETTING(_profile, RightClickContextMenu);
Expand Down Expand Up @@ -154,7 +173,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
winrt::hstring _lastIconPath;
Windows::Foundation::IInspectable _currentIconType{};
Editor::AppearanceViewModel _defaultAppearanceViewModel;
Windows::UI::Core::CoreDispatcher _dispatcher;

void _InitializeCurrentBellSounds();
void _PrepareModelForBellSoundModification();
void _MarkDuplicateBellSoundDirectories();
safe_void_coroutine _CheckBellSoundsExistence();
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;
static Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> _BuiltInIcons;
Expand Down
Loading
Loading