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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
11 changes: 11 additions & 0 deletions src/cascadia/TerminalSettingsEditor/CommonResources.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,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
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsEditor/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,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
202 changes: 202 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ProfileViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
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");

_InitializeCurrentBellSounds();

// Add a property changed handler to our own property changed event.
// This propagates changes from the settings model to anybody listening to our
// unique view model members.
Expand Down Expand Up @@ -76,6 +78,21 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
{
_NotifyChanges(L"HideIcon");
}
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()

_NotifyChanges(L"BellSoundPreview", L"HasBellSound");
}
else if (viewModelProperty == L"BellSound")
{
_InitializeCurrentBellSounds();
}
});

// Do the same for the starting directory
Expand Down Expand Up @@ -374,6 +391,191 @@ 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)
{
auto vm = winrt::make<BellSoundViewModel>(bellSound);
vm.PropertyChanged({ this, &ProfileViewModel::_BellSoundVMPropertyChanged });
_CurrentBellSounds.Append(vm);
}
}
_CurrentBellSounds.VectorChanged([this](auto&&, const IVectorChangedEventArgs& args) {
carlos-zamora marked this conversation as resolved.
Show resolved Hide resolved
switch (args.CollectionChange())
{
case CollectionChange::ItemInserted:
{
const auto index = args.Index();
const auto& newSound = _CurrentBellSounds.GetAt(index);

if (!_profile.BellSound())
{
_profile.BellSound(winrt::single_threaded_vector<winrt::hstring>());
}
_profile.BellSound().InsertAt(index, newSound.Path());
break;
}
case CollectionChange::ItemRemoved:
{
_profile.BellSound().RemoveAt(args.Index());
break;
}
case CollectionChange::ItemChanged:
{
// I've never been able to get this one to hit,
// but if it ever does, propagate change to model
const auto index = args.Index();
const auto& newSound = _CurrentBellSounds.GetAt(index);
_profile.BellSound().SetAt(index, newSound.Path());
break;
}
case CollectionChange::Reset:
default:
{
// propagate changes to model
auto list = winrt::single_threaded_vector<winrt::hstring>();
for (const auto& sound : _CurrentBellSounds)
{
list.Append(sound.Path());
}
_profile.BellSound(list);
break;
}
}
});
_MarkDuplicateBellSoundDirectories();
_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 (const auto inheritedSounds = _profile.BellSound(); !_profile.HasBellSound() && inheritedSounds)
{
auto newSounds{ winrt::single_threaded_vector<winrt::hstring>() };
for (const auto sound : inheritedSounds)
{
newSounds.Append(sound);
}
_profile.BellSound(newSounds);
}
}

void ProfileViewModel::_MarkDuplicateBellSoundDirectories()
{
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>(_CurrentBellSounds.GetAt(i))->ShowDirectory(true);
get_self<BellSoundViewModel>(_CurrentBellSounds.GetAt(j))->ShowDirectory(true);
}
}
}
}

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

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

bool BellSoundViewModel::FileExists() const
{
return std::filesystem::exists(std::wstring_view{ _Path });
}

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::_BellSoundVMPropertyChanged(const IInspectable& sender, const PropertyChangedEventArgs& args)
{
if (args.PropertyName() == L"Path")
{
auto senderVM = sender.as<Editor::BellSoundViewModel>();

// propagate changes to model
uint32_t index;
if (_CurrentBellSounds.IndexOf(senderVM, index))
{
// if current layer is inheriting,
// we should copy the bell sound then apply changes
_PrepareModelForBellSoundModification();

_profile.BellSound().SetAt(index, senderVM.Path());
_NotifyChanges(L"CurrentBellSounds");
}
}
}

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

auto vm = winrt::make<BellSoundViewModel>();
vm.Path(path);
vm.PropertyChanged({ this, &ProfileViewModel::_BellSoundVMPropertyChanged });
_CurrentBellSounds.Append(vm);
_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();

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

void ProfileViewModel::DeleteProfile()
{
auto deleteProfileArgs{ winrt::make_self<DeleteProfileEventArgs>(Guid()) };
Expand Down
33 changes: 33 additions & 0 deletions 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,28 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Editor::ProfileViewModel _Profile{ nullptr };
};

struct BellSoundViewModel : BellSoundViewModelT<BellSoundViewModel>, ViewModelHelper<BellSoundViewModel>
{
public:
BellSoundViewModel() = default;
BellSoundViewModel(hstring path) :
_Path{ path }
{
PropertyChanged([this](auto&&, auto&& e) {
if (e.PropertyName() == L"Path")
{
_NotifyChanges(L"DisplayPath", L"SubText", L"FileExists", L"ShowSubText");
}
});
}

hstring DisplayPath() const;
hstring SubText() const;
bool FileExists() const;
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, Path);
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, ShowDirectory);
};

struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
Expand All @@ -46,6 +69,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 @@ -88,6 +115,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);

PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, Guid);
PERMANENT_OBSERVABLE_PROJECTED_SETTING(_profile, ConnectionType);
Expand All @@ -114,6 +142,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 All @@ -139,6 +168,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
winrt::hstring _lastIcon;
Editor::AppearanceViewModel _defaultAppearanceViewModel;

void _InitializeCurrentBellSounds();
void _PrepareModelForBellSoundModification();
void _MarkDuplicateBellSoundDirectories();
void _BellSoundVMPropertyChanged(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args);
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _MonospaceFontList;
static Windows::Foundation::Collections::IObservableVector<Editor::Font> _FontList;

Expand Down
15 changes: 15 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ namespace Microsoft.Terminal.Settings.Editor
Guid ProfileGuid { get; };
}

runtimeclass BellSoundViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Path;
String DisplayPath { get; };
String SubText { get; };
Boolean ShowDirectory { get; };
Boolean FileExists { get; };
}

enum ProfileSubPage
{
Base = 0,
Expand All @@ -49,6 +58,11 @@ namespace Microsoft.Terminal.Settings.Editor
void SetBellStyleWindow(Windows.Foundation.IReference<Boolean> on);
void SetBellStyleTaskbar(Windows.Foundation.IReference<Boolean> on);

String BellSoundPreview { get; };
Windows.Foundation.Collections.IObservableVector<BellSoundViewModel> CurrentBellSounds { get; };
void RequestAddBellSound(String path);
void RequestDeleteBellSound(BellSoundViewModel vm);

IInspectable CurrentAntiAliasingMode;
Windows.Foundation.Collections.IObservableVector<Microsoft.Terminal.Settings.Editor.EnumEntry> AntiAliasingModeList { get; };

Expand Down Expand Up @@ -106,6 +120,7 @@ namespace Microsoft.Terminal.Settings.Editor
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, SnapOnInput);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, AltGrAliasing);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Microsoft.Terminal.Settings.Model.BellStyle, BellStyle);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Windows.Foundation.Collections.IVector<String>, BellSound);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, Elevate);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, ReloadEnvironmentVariables);
OBSERVABLE_PROJECTED_PROFILE_SETTING(Boolean, RightClickContextMenu);
Expand Down
Loading
Loading