Skip to content

Commit

Permalink
Add Profile.BellSound to Settings UI
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-zamora committed Oct 1, 2024
1 parent a7e47b7 commit 8d2791f
Show file tree
Hide file tree
Showing 8 changed files with 336 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsEditor/MainPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,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
156 changes: 156 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,145 @@ 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) {
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;
}
}
});
_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);
}
}

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()
{
// If we were inheriting our bell sound,
// copy it over to the current layer and apply modifications
_PrepareModelForBellSoundModification();

auto vm = winrt::make<BellSoundViewModel>();
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
20 changes: 20 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,16 @@ 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 } {}

VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, Path);
};

struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
{
public:
Expand All @@ -46,6 +57,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();
void RequestDeleteBellSound(const Editor::BellSoundViewModel& vm);

void SetAcrylicOpacityPercentageValue(double value)
{
Opacity(static_cast<float>(value) / 100.0f);
Expand Down Expand Up @@ -88,6 +103,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 +130,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 @@ -135,6 +152,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
winrt::hstring _lastIcon;
Editor::AppearanceViewModel _defaultAppearanceViewModel;

void _InitializeCurrentBellSounds();
void _PrepareModelForBellSoundModification();
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
11 changes: 11 additions & 0 deletions src/cascadia/TerminalSettingsEditor/ProfileViewModel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ namespace Microsoft.Terminal.Settings.Editor
Guid ProfileGuid { get; };
}

runtimeclass BellSoundViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
{
String Path;
}

enum ProfileSubPage
{
Base = 0,
Expand All @@ -48,6 +53,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();
void RequestDeleteBellSound(BellSoundViewModel vm);

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

Expand Down Expand Up @@ -105,6 +115,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
52 changes: 51 additions & 1 deletion src/cascadia/TerminalSettingsEditor/Profiles_Advanced.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <LibraryResources.h>
#include "..\WinRTUtils\inc\Utils.h"

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Navigation;

namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
Expand All @@ -21,11 +24,58 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

void Profiles_Advanced::OnNavigatedTo(const NavigationEventArgs& e)
{
_Profile = e.Parameter().as<Editor::ProfileViewModel>();
const auto args = e.Parameter().as<Editor::NavigateToProfileArgs>();
_Profile = args.Profile();
_windowRoot = args.WindowRoot();

//if (const auto& bellSounds = _Profile.CurrentBellSounds())
//{
// auto uiStack = BellSoundStack().Children();
// const auto dataTemplate = Resources().Lookup(box_value(L"BellSoundEntryViewModelTemplate")).as<DataTemplate>();
// for (const auto&& entry : bellSounds)
// {
// ContentControl ctrl;
// ctrl.Content(entry);
// ctrl.ContentTemplate(dataTemplate);
//
// uiStack.Append(ctrl);
// }
//}
}

void Profiles_Advanced::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
{
_ViewModelChangedRevoker.revoke();
}

safe_void_coroutine Profiles_Advanced::BellSoundBrowse_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
{
static constexpr COMDLG_FILTERSPEC supportedFileTypes[] = {
{ L"Sound Files (*.wav;*.mp3;*.flac)", L"*.wav;*.mp3;*.flac" },
{ L"All Files (*.*)", L"*.*" }
};

const auto parentHwnd{ reinterpret_cast<HWND>(WindowRoot().GetHostingWindow()) };
auto file = co_await OpenFilePicker(parentHwnd, [](auto&& dialog) {
try
{
auto folderShellItem{ winrt::capture<IShellItem>(&SHGetKnownFolderItem, FOLDERID_Music, KF_FLAG_DEFAULT, nullptr) };
dialog->SetDefaultFolder(folderShellItem.get());
}
CATCH_LOG(); // non-fatal
THROW_IF_FAILED(dialog->SetFileTypes(ARRAYSIZE(supportedFileTypes), supportedFileTypes));
THROW_IF_FAILED(dialog->SetFileTypeIndex(1)); // the array is 1-indexed
THROW_IF_FAILED(dialog->SetDefaultExtension(L"wav;mp3;flac"));
});
if (!file.empty())
{
sender.as<Button>().Tag().as<Editor::BellSoundViewModel>().Path(file);
}
}

void Profiles_Advanced::BellSoundDelete_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
{
auto bellSoundEntry = sender.as<Button>().Tag().as<Editor::BellSoundViewModel>();
_Profile.RequestDeleteBellSound(bellSoundEntry);
}
}
5 changes: 5 additions & 0 deletions src/cascadia/TerminalSettingsEditor/Profiles_Advanced.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
void OnNavigatedTo(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);
void OnNavigatedFrom(const Windows::UI::Xaml::Navigation::NavigationEventArgs& e);

safe_void_coroutine BellSoundBrowse_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);
void BellSoundDelete_Click(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& e);

til::property_changed_event PropertyChanged;
Editor::IHostedInWindow WindowRoot() { return _windowRoot; };
WINRT_PROPERTY(Editor::ProfileViewModel, Profile, nullptr);

private:
Windows::UI::Xaml::Data::INotifyPropertyChanged::PropertyChanged_revoker _ViewModelChangedRevoker;
Editor::IHostedInWindow _windowRoot;
};
};

Expand Down
Loading

1 comment on commit 8d2791f

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@check-spelling-bot Report

🔴 Please review

See the 📜action log or 📝 job summary for details.

Unrecognized words (1)

flac

Previously acknowledged words that are now absent vtio vtpt 🫥
To accept these unrecognized words as correct and remove the previously acknowledged and now absent words, you could run the following commands

... in a clone of the git@github.com:microsoft/terminal.git repository
on the dev/cazamor/SUI/bell-sound branch (ℹ️ how do I use this?):

curl -s -S -L 'https://raw.githubusercontent.com/check-spelling/check-spelling/v0.0.22/apply.pl' |
perl - 'https://github.com/microsoft/terminal/actions/runs/11130946207/attempts/1'
Available 📚 dictionaries could cover words (expected and unrecognized) not in the 📘 dictionary

This includes both expected items (2221) from .github/actions/spelling/expect/04cdb9b77d6827c0202f51acd4205b017015bfff.txt
.github/actions/spelling/expect/alphabet.txt
.github/actions/spelling/expect/expect.txt
.github/actions/spelling/expect/web.txt and unrecognized words (1)

Dictionary Entries Covers Uniquely
cspell:cpp/src/lang-jargon.txt 11 1 1
cspell:swift/src/swift.txt 53 1 1
cspell:gaming-terms/dict/gaming-terms.txt 59 1 1
cspell:monkeyc/src/monkeyc_keywords.txt 123 1 1
cspell:cryptocurrencies/cryptocurrencies.txt 125 1 1

Consider adding them (in .github/workflows/spelling2.yml) for uses: check-spelling/check-spelling@v0.0.22 in its with:

      with:
        extra_dictionaries:
          cspell:cpp/src/lang-jargon.txt
          cspell:swift/src/swift.txt
          cspell:gaming-terms/dict/gaming-terms.txt
          cspell:monkeyc/src/monkeyc_keywords.txt
          cspell:cryptocurrencies/cryptocurrencies.txt

To stop checking additional dictionaries, add (in .github/workflows/spelling2.yml) for uses: check-spelling/check-spelling@v0.0.22 in its with:

check_extra_dictionaries: ''
Errors (1)

See the 📜action log or 📝 job summary for details.

❌ Errors Count
❌ ignored-expect-variant 6

See ❌ Event descriptions for more information.

✏️ Contributor please read this

By default the command suggestion will generate a file named based on your commit. That's generally ok as long as you add the file to your commit. Someone can reorganize it later.

If the listed items are:

  • ... misspelled, then please correct them instead of using the command.
  • ... names, please add them to .github/actions/spelling/allow/names.txt.
  • ... APIs, you can add them to a file in .github/actions/spelling/allow/.
  • ... just things you're using, please add them to an appropriate file in .github/actions/spelling/expect/.
  • ... tokens you only need in one place and shouldn't generally be used, you can add an item in an appropriate file in .github/actions/spelling/patterns/.

See the README.md in each directory for more information.

🔬 You can test your commits without appending to a PR by creating a new branch with that extra change and pushing it to your fork. The check-spelling action will run in response to your push -- it doesn't require an open pull request. By using such a branch, you can limit the number of typos your peers see you make. 😉

If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Please sign in to comment.