mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Add Profile.BellSound to Settings UI (#17983)
## Summary of the Pull Request Adds the Profile.BellSound setting to the Settings UI under the Profile > Advanced page. - View changes: - The setting is exposed via an expander placed near the Profile.BellStyle setting. - Added a button to be able to preview the added sound - Added a browse button that opens a file picker - Added a delete button to be able to delete each sound entry - View model changes: - `CurrentBellSounds` keeps track of the bell sounds added and exposed via the UI. - `BellSoundViewModel` wraps each sound. This allows us to listen (and propagate) changes to the registered sounds. - `BellSoundPreview` provides a written preview of the current bell sound to display in the expander #10000
This commit is contained in:
parent
8bbf00e054
commit
8ef77fba3b
1
.github/actions/spelling/allow/allow.txt
vendored
1
.github/actions/spelling/allow/allow.txt
vendored
@ -23,6 +23,7 @@ dzhe
|
||||
Emacspeak
|
||||
Fitt
|
||||
FTCS
|
||||
flac
|
||||
gantt
|
||||
gfm
|
||||
ghe
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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) :
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
@ -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) };
|
||||
|
||||
|
||||
@ -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);
|
||||
@ -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");
|
||||
@ -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())
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
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();
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
|
||||
@ -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"
|
||||
@ -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);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(hstring, Path);
|
||||
VIEW_MODEL_OBSERVABLE_PROPERTY(bool, ShowDirectory);
|
||||
};
|
||||
|
||||
struct ProfileViewModel : ProfileViewModelT<ProfileViewModel>, ViewModelHelper<ProfileViewModel>
|
||||
{
|
||||
public:
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
@ -56,6 +65,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; };
|
||||
|
||||
@ -129,6 +143,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);
|
||||
|
||||
@ -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
|
||||
@ -17,15 +20,88 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
||||
Profiles_Advanced::Profiles_Advanced()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Automation::AutomationProperties::SetName(AddBellSoundButton(), RS_(L"Profile_AddBellSound/Text"));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void Profiles_Advanced::OnNavigatedFrom(const NavigationEventArgs& /*e*/)
|
||||
{
|
||||
_ViewModelChangedRevoker.revoke();
|
||||
}
|
||||
|
||||
safe_void_coroutine Profiles_Advanced::BellSoundAudioPreview_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
|
||||
try
|
||||
{
|
||||
const auto path = sender.as<Button>().Tag().as<Editor::BellSoundViewModel>().Path();
|
||||
if (path.empty())
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
const winrt::hstring soundPath{ wil::ExpandEnvironmentStringsW<std::wstring>(path.c_str()) };
|
||||
const winrt::Windows::Foundation::Uri uri{ soundPath };
|
||||
|
||||
if (!_bellPlayerCreated)
|
||||
{
|
||||
// The MediaPlayer might not exist on Windows N SKU.
|
||||
try
|
||||
{
|
||||
_bellPlayerCreated = true;
|
||||
_bellPlayer = winrt::Windows::Media::Playback::MediaPlayer();
|
||||
// GH#12258: The media keys (like play/pause) should have no effect on our bell sound.
|
||||
_bellPlayer.CommandManager().IsEnabled(false);
|
||||
}
|
||||
CATCH_LOG();
|
||||
}
|
||||
if (_bellPlayer)
|
||||
{
|
||||
const auto source{ winrt::Windows::Media::Core::MediaSource::CreateFromUri(uri) };
|
||||
const auto item{ winrt::Windows::Media::Playback::MediaPlaybackItem(source) };
|
||||
_bellPlayer.Source(item);
|
||||
_bellPlayer.Play();
|
||||
}
|
||||
}
|
||||
CATCH_LOG();
|
||||
|
||||
void Profiles_Advanced::BellSoundDelete_Click(const IInspectable& sender, const RoutedEventArgs& /*e*/)
|
||||
{
|
||||
const auto bellSoundEntry = sender.as<Button>().Tag().as<Editor::BellSoundViewModel>();
|
||||
_Profile.RequestDeleteBellSound(bellSoundEntry);
|
||||
}
|
||||
|
||||
void Profiles_Advanced::BellSoundAdd_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*e*/)
|
||||
{
|
||||
_PickFileForBellSound();
|
||||
}
|
||||
|
||||
safe_void_coroutine Profiles_Advanced::_PickFileForBellSound()
|
||||
{
|
||||
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())
|
||||
{
|
||||
_Profile.RequestAddBellSound(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,11 +17,21 @@ 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 BellSoundAudioPreview_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);
|
||||
void BellSoundAdd_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;
|
||||
winrt::Windows::Media::Playback::MediaPlayer _bellPlayer{ nullptr };
|
||||
bool _bellPlayerCreated{ false };
|
||||
|
||||
safe_void_coroutine _PickFileForBellSound();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:model="using:Microsoft.Terminal.Settings.Model"
|
||||
xmlns:mtu="using:Microsoft.Terminal.UI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@ -108,6 +109,87 @@
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- Bell Sound -->
|
||||
<local:SettingContainer x:Uid="Profile_BellSound"
|
||||
ClearSettingValue="{x:Bind Profile.ClearBellSound}"
|
||||
CurrentValue="{x:Bind Profile.BellSoundPreview, Mode=OneWay}"
|
||||
HasSettingValue="{x:Bind Profile.HasBellSound, Mode=OneWay}"
|
||||
SettingOverrideSource="{x:Bind Profile.BellSoundOverrideSource, Mode=OneWay}"
|
||||
Style="{StaticResource ExpanderSettingContainerStyle}">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock x:Uid="Profile_BellSoundInfo"
|
||||
Style="{StaticResource DisclaimerStyle}" />
|
||||
<ItemsControl ItemsSource="{x:Bind Profile.CurrentBellSounds, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Spacing="5" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:BellSoundViewModel">
|
||||
<Grid TabFocusNavigation="Local">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="300" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- standard UI for bell sound entry -->
|
||||
<StackPanel Grid.Column="0"
|
||||
Visibility="{x:Bind FileExists, Mode=OneWay}">
|
||||
<TextBlock Style="{StaticResource TextBlockSettingStyle}"
|
||||
Text="{x:Bind DisplayPath, Mode=OneWay}" />
|
||||
<TextBlock Foreground="{ThemeResource SubgroupHeaderBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SubText, Mode=OneWay}"
|
||||
Visibility="{x:Bind ShowDirectory, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<!-- When a file is not found, we use this UI -->
|
||||
<StackPanel Grid.Column="0"
|
||||
Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(FileExists), Mode=OneWay}">
|
||||
<TextBlock Style="{StaticResource TextBlockSettingStyle}"
|
||||
Text="{x:Bind DisplayPath, Mode=OneWay}"
|
||||
TextDecorations="Strikethrough" />
|
||||
<TextBlock Foreground="{ThemeResource SubgroupHeaderBrush}"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{x:Bind SubText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
<Button x:Uid="Profile_BellSoundAudioPreview"
|
||||
Grid.Column="1"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Click="BellSoundAudioPreview_Click"
|
||||
IsEnabled="{x:Bind FileExists, Mode=OneWay}"
|
||||
Style="{StaticResource BrowseButtonStyle}"
|
||||
Tag="{Binding Mode=OneWay}">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
<Button x:Uid="Profile_BellSoundDelete"
|
||||
Grid.Column="2"
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Stretch"
|
||||
Click="BellSoundDelete_Click"
|
||||
Style="{StaticResource DeleteButtonStyle}"
|
||||
Tag="{Binding Mode=OneWay}">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Button x:Name="AddBellSoundButton"
|
||||
Click="BellSoundAdd_Click">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="{StaticResource StandardIconSize}"
|
||||
Glyph="" />
|
||||
<TextBlock x:Uid="Profile_AddBellSound"
|
||||
Margin="10,0,0,0" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</local:SettingContainer>
|
||||
|
||||
<!-- RightClickContextMenu -->
|
||||
<local:SettingContainer x:Uid="Profile_RightClickContextMenu"
|
||||
ClearSettingValue="{x:Bind Profile.ClearRightClickContextMenu}"
|
||||
|
||||
@ -1929,6 +1929,53 @@
|
||||
<value>Non-monospace fonts:</value>
|
||||
<comment>This is a label that is followed by a list of proportional fonts.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundPreviewDefault" xml:space="preserve">
|
||||
<value>Default system sound</value>
|
||||
<comment>The value shown for the default value for bell sound.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundPreviewMultiple" xml:space="preserve">
|
||||
<value>Multiple sounds</value>
|
||||
<comment>The value shown for when the "bell sound" setting is set to multiple values.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSound.Header" xml:space="preserve">
|
||||
<value>Bell sound</value>
|
||||
<comment>Header for a control to determine what sound the app uses to notify the user. "Bell" is the common term in terminals for the BEL character (like the metal device used to chime).</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSound.HelpText" xml:space="preserve">
|
||||
<value>Controls what sound is played when the application emits a BEL character. "Bell notification style" must include "Audible".</value>
|
||||
<comment>A description for what the "bell sound" setting does. Presented near "Profile_BellSound". "Bell notification style" and "audible" come from "Profile_BellStyle" and "Profile_BellStyleAudible.Content" respectively.{Locked="BEL"}</comment>
|
||||
</data>
|
||||
<data name="Profile_AddBellSound.Text" xml:space="preserve">
|
||||
<value>Add sound</value>
|
||||
<comment>Text label for a button that adds a sound to the bell sound list. Presented near "Profile_BellSound"</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundBrowse.Content" xml:space="preserve">
|
||||
<value>Browse...</value>
|
||||
<comment>Text label for a button that opens a file picker to select a sound file to use for the bell sound. Presented near "Profile_BellSound".</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundInfo.Text" xml:space="preserve">
|
||||
<value>When multiple sounds are defined, one is selected at random when the BEL character is received.</value>
|
||||
<comment>{Locked="BEL"} Text block displayed near "Profile_BellSound".</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundNotFound" xml:space="preserve">
|
||||
<value>⚠️ File not found</value>
|
||||
</data>
|
||||
<data name="Profile_BellSoundAudioPreview.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Play sound</value>
|
||||
<comment>Tooltip for a button that plays the selected sound when pressed.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundDelete.[using:Windows.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
<comment>Tooltip for a button that deletes the selected sound when pressed.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundAudioPreview.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Play sound</value>
|
||||
<comment>Screen reader name for a button that plays the selected sound when pressed.</comment>
|
||||
</data>
|
||||
<data name="Profile_BellSoundDelete.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
<comment>Screen reader name for a button that deletes the selected sound when pressed.</comment>
|
||||
</data>
|
||||
<data name="Profile_TabColor.Header" xml:space="preserve">
|
||||
<value>Tab color</value>
|
||||
<comment>Header for a control to determine the color of the tab.</comment>
|
||||
|
||||
@ -44,6 +44,10 @@
|
||||
#include <winrt/Windows.UI.Xaml.Media.h>
|
||||
#include <winrt/Windows.UI.Xaml.Navigation.h>
|
||||
|
||||
#include <winrt/Windows.Media.h>
|
||||
#include <winrt/Windows.Media.Core.h>
|
||||
#include <winrt/Windows.Media.Playback.h>
|
||||
|
||||
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
||||
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
||||
|
||||
@ -61,3 +65,4 @@
|
||||
#include <til/winrt.h>
|
||||
|
||||
#include <cppwinrt_utils.h>
|
||||
#include <wil/cppwinrt_helpers.h> // must go after the CoreDispatcher type is defined
|
||||
|
||||
@ -123,6 +123,18 @@ winrt::com_ptr<Profile> Profile::CopySettings() const
|
||||
MTSM_PROFILE_SETTINGS(PROFILE_SETTINGS_COPY)
|
||||
#undef PROFILE_SETTINGS_COPY
|
||||
|
||||
// BellSound is an IVector<hstring>, so we need to manually copy it over
|
||||
if (_BellSound)
|
||||
{
|
||||
std::vector<hstring> sounds;
|
||||
sounds.reserve(_BellSound->Size());
|
||||
for (const auto& sound : *_BellSound)
|
||||
{
|
||||
sounds.emplace_back(sound);
|
||||
}
|
||||
profile->_BellSound = single_threaded_vector(std::move(sounds));
|
||||
}
|
||||
|
||||
if (_UnfocusedAppearance)
|
||||
{
|
||||
Model::AppearanceConfig unfocused{ nullptr };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user