diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp index be70d51c19..4897a1e73e 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.cpp @@ -44,6 +44,37 @@ using namespace winrt::Microsoft::Terminal::Settings::Model; std::sort(enumList.begin(), enumList.end(), EnumEntryReverseComparator()); \ _EnumList = winrt::single_threaded_observable_vector(std::move(enumList)); +#define INITIALIZE_FLAG_LIST_AND_VALUE(enumMappingsName, enumType, resourceSectionAndType, resourceProperty) \ + std::vector flagList; \ + const auto mappings = winrt::Microsoft::Terminal::Settings::Model::EnumMappings::enumMappingsName(); \ + enumType unboxedValue; \ + if (value) \ + { \ + unboxedValue = unbox_value(value); \ + } \ + for (const auto [flagKey, flagValue] : mappings) \ + { \ + if (flagKey != L"all" && flagKey != L"none") \ + { \ + const auto flagName = LocalizedNameForEnumName(resourceSectionAndType, flagKey, resourceProperty); \ + bool isSet = value ? WI_IsAnyFlagSet(unboxedValue, flagValue) : false; \ + auto entry = winrt::make(flagName, winrt::box_value(flagValue), isSet); \ + entry.PropertyChanged([&, flagValue](const IInspectable& sender, const PropertyChangedEventArgs& args) { \ + const auto itemProperty{ args.PropertyName() }; \ + if (itemProperty == L"IsSet") \ + { \ + const auto flagWrapper = sender.as(); \ + auto unboxed = unbox_value(_Value); \ + flagWrapper.IsSet() ? WI_SetAllFlags(unboxed, flagValue) : WI_ClearAllFlags(unboxed, flagValue); \ + Value(box_value(unboxed)); \ + } \ + }); \ + flagList.emplace_back(entry); \ + } \ + } \ + std::sort(flagList.begin(), flagList.end(), FlagEntryReverseComparator()); \ + _FlagList = winrt::single_threaded_observable_vector(std::move(flagList)); + namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { KeyBindingViewModel::KeyBindingViewModel(const IObservableVector& availableActions) : @@ -175,7 +206,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation const auto emptyArgs = CascadiaSettings::GetEmptyArgsForAction(actionEnum); // todo: for sendInput, where "input" is a required argument, this will set it to an empty string which does not satisfy the requirement // i.e. if the user hits "save" immediately after switching to sendInput as the action (without adding something to the input field), they'll get an error - emptyArgs.SetAllArgsToDefault(); + if (emptyArgs) + { + emptyArgs.SetAllArgsToDefault(); + } Model::ActionAndArgs newActionAndArgs{ actionEnum, emptyArgs }; _command.ActionAndArgs(newActionAndArgs); ActionArgsVM(make(newActionAndArgs)); @@ -256,9 +290,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation }); } - ArgWrapper::ArgWrapper(const winrt::hstring& type, const bool required, const Windows::Foundation::IInspectable& value) + ArgWrapper::ArgWrapper(const winrt::hstring& name, const winrt::hstring& type, const bool required, const Windows::Foundation::IInspectable& value) { Value(value); + _name = name; _type = type; _required = required; if (_type == L"Model::ResizeDirection") @@ -287,7 +322,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation } else if (_type == L"SuggestionsSource") { - INITIALIZE_ENUM_LIST_AND_VALUE(SuggestionsSource, Model::SuggestionsSource, L"Actions_SuggestionsSource", L"Content"); + INITIALIZE_FLAG_LIST_AND_VALUE(SuggestionsSource, Model::SuggestionsSource, L"Actions_SuggestionsSource", L"Content"); } else if (_type == L"FindMatchDirection") { @@ -324,7 +359,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation if (_EnumValue != enumValue) { _EnumValue = enumValue; - Value(enumValue.as().EnumValue()); + Value(_EnumValue.as().EnumValue()); } } @@ -342,9 +377,10 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { const auto argAtIndex = shortcutArgs.GetArgAt(i); const auto argDescription = shortcutArgs.GetArgDescriptionAt(i); + const auto argName = argDescription.Name; const auto argType = argDescription.Type; const auto argRequired = argDescription.Required; - const auto item = make(argType, argRequired, argAtIndex); + const auto item = make(argName, argType, argRequired, argAtIndex); item.PropertyChanged([&, i](const IInspectable& sender, const PropertyChangedEventArgs& args) { const auto itemProperty{ args.PropertyName() }; if (itemProperty == L"Value") diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h index 2510d569e5..b8f1aed11f 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.h @@ -168,7 +168,9 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation struct ArgWrapper : ArgWrapperT, ViewModelHelper { public: - ArgWrapper(const winrt::hstring& type, const bool required, const Windows::Foundation::IInspectable& value); + ArgWrapper(const winrt::hstring& name, const winrt::hstring& type, const bool required, const Windows::Foundation::IInspectable& value); + + winrt::hstring Name() const noexcept { return _name; }; winrt::hstring Type() const noexcept { return _type; }; @@ -176,6 +178,8 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation Windows::Foundation::Collections::IObservableVector EnumList() const noexcept { return _EnumList; }; + Windows::Foundation::Collections::IObservableVector FlagList() const noexcept { return _FlagList; }; + void StringBindBack(const winrt::hstring& newValue) { Value(box_value(newValue)); }; void DoubleBindBack(const double newValue) { Value(box_value(static_cast(newValue))); }; @@ -203,10 +207,12 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation VIEW_MODEL_OBSERVABLE_PROPERTY(Windows::Foundation::IInspectable, Value, nullptr); private: + winrt::hstring _name; winrt::hstring _type; bool _required; Windows::Foundation::IInspectable _EnumValue{ nullptr }; Windows::Foundation::Collections::IObservableVector _EnumList; + Windows::Foundation::Collections::IObservableVector _FlagList; }; struct ActionArgsViewModel : ActionArgsViewModelT, ViewModelHelper diff --git a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl index ae1100c6ab..75c2147bdf 100644 --- a/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl +++ b/src/cascadia/TerminalSettingsEditor/ActionsViewModel.idl @@ -78,11 +78,13 @@ namespace Microsoft.Terminal.Settings.Editor runtimeclass ArgWrapper : Windows.UI.Xaml.Data.INotifyPropertyChanged { + String Name { get; }; String Type { get; }; Boolean Required { get; }; IInspectable Value; IInspectable EnumValue; Windows.Foundation.Collections.IObservableVector EnumList { get; }; + Windows.Foundation.Collections.IObservableVector FlagList { get; }; void StringBindBack(String newValue); void DoubleBindBack(Double newValue); void DoubleOptionalBindBack(Double newValue); diff --git a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp index 6729d633c8..cdf77ea92d 100644 --- a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp +++ b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.cpp @@ -63,7 +63,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation argType == L"MoveTabDirection" || argType == L"Microsoft::Terminal::Control::ScrollToMarkDirection" || argType == L"CommandPaletteLaunchMode" || - argType == L"SuggestionsSource" || argType == L"FindMatchDirection" || argType == L"Model::DesktopBehavior" || argType == L"Model::MonitorBehavior" || @@ -72,11 +71,15 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation { return EnumTemplate(); } + else if (argType == L"SuggestionsSource") + { + return FlagTemplate(); + } else if (argType == L"Windows::Foundation::IReference") { return nullptr; } } - return nullptr; + return NoArgTemplate(); } } diff --git a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.h b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.h index c90e244fa4..de500bba7d 100644 --- a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.h +++ b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.h @@ -14,6 +14,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation Windows::UI::Xaml::DataTemplate SelectTemplateCore(const winrt::Windows::Foundation::IInspectable&, const winrt::Windows::UI::Xaml::DependencyObject&); Windows::UI::Xaml::DataTemplate SelectTemplateCore(const winrt::Windows::Foundation::IInspectable&); + WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, NoArgTemplate); WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, Int32Template); WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, UInt32Template); WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, UInt32OptionalTemplate); @@ -22,6 +23,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, BoolTemplate); WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, BoolOptionalTemplate); WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, EnumTemplate); + WINRT_PROPERTY(winrt::Windows::UI::Xaml::DataTemplate, FlagTemplate); }; } diff --git a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.idl b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.idl index 90d1b34dfc..63bbe78aca 100644 --- a/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.idl +++ b/src/cascadia/TerminalSettingsEditor/ArgsTemplateSelectors.idl @@ -7,6 +7,7 @@ namespace Microsoft.Terminal.Settings.Editor { ArgsTemplateSelectors(); + Windows.UI.Xaml.DataTemplate NoArgTemplate; Windows.UI.Xaml.DataTemplate Int32Template; Windows.UI.Xaml.DataTemplate UInt32Template; Windows.UI.Xaml.DataTemplate UInt32OptionalTemplate; @@ -15,5 +16,6 @@ namespace Microsoft.Terminal.Settings.Editor Windows.UI.Xaml.DataTemplate BoolTemplate; Windows.UI.Xaml.DataTemplate BoolOptionalTemplate; Windows.UI.Xaml.DataTemplate EnumTemplate; + Windows.UI.Xaml.DataTemplate FlagTemplate; } } diff --git a/src/cascadia/TerminalSettingsEditor/EditAction.xaml b/src/cascadia/TerminalSettingsEditor/EditAction.xaml index 80ab51c434..fb679293e2 100644 --- a/src/cascadia/TerminalSettingsEditor/EditAction.xaml +++ b/src/cascadia/TerminalSettingsEditor/EditAction.xaml @@ -225,10 +225,18 @@ + + + + - + + - + + - + + - + + - + + @@ -293,7 +313,10 @@ - + + @@ -302,7 +325,10 @@ - + + @@ -317,7 +343,10 @@ - + + + + + + + + + + + + + + + + + + + EnumTemplate="{StaticResource EnumTemplate}" + FlagTemplate="{StaticResource FlagTemplate}" /> @@ -358,7 +412,9 @@ ChoosingItemContainer="_choosingItemContainer" SelectionMode="None" AllowDrop="False" - CanReorderItems="False" /> + CanDragItems="False" + CanReorderItems="False"> + diff --git a/src/cascadia/TerminalSettingsEditor/EnumEntry.h b/src/cascadia/TerminalSettingsEditor/EnumEntry.h index fe45a58396..fc67734954 100644 --- a/src/cascadia/TerminalSettingsEditor/EnumEntry.h +++ b/src/cascadia/TerminalSettingsEditor/EnumEntry.h @@ -17,6 +17,7 @@ Author(s): #pragma once #include "EnumEntry.g.h" +#include "FlagEntry.g.h" #include "Utils.h" namespace winrt::Microsoft::Terminal::Settings::Editor::implementation @@ -55,4 +56,41 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation WINRT_OBSERVABLE_PROPERTY(winrt::hstring, EnumName, PropertyChanged.raise); WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::IInspectable, EnumValue, PropertyChanged.raise); }; + + template + struct FlagEntryComparator + { + bool operator()(const Editor::FlagEntry& lhs, const Editor::FlagEntry& rhs) const + { + return lhs.FlagValue().as() < rhs.FlagValue().as(); + } + }; + + template + struct FlagEntryReverseComparator + { + bool operator()(const Editor::FlagEntry& lhs, const Editor::FlagEntry& rhs) const + { + return lhs.FlagValue().as() > rhs.FlagValue().as(); + } + }; + + struct FlagEntry : FlagEntryT + { + public: + FlagEntry(const winrt::hstring flagName, const winrt::Windows::Foundation::IInspectable& flagValue, const bool isSet) : + _FlagName{ flagName }, + _FlagValue{ flagValue }, + _IsSet{ isSet } {} + + hstring ToString() + { + return FlagName(); + } + + til::property_changed_event PropertyChanged; + WINRT_OBSERVABLE_PROPERTY(winrt::hstring, FlagName, PropertyChanged.raise); + WINRT_OBSERVABLE_PROPERTY(winrt::Windows::Foundation::IInspectable, FlagValue, PropertyChanged.raise); + WINRT_OBSERVABLE_PROPERTY(bool, IsSet, PropertyChanged.raise); + }; } diff --git a/src/cascadia/TerminalSettingsEditor/EnumEntry.idl b/src/cascadia/TerminalSettingsEditor/EnumEntry.idl index ce92d75762..c27e5ea6c3 100644 --- a/src/cascadia/TerminalSettingsEditor/EnumEntry.idl +++ b/src/cascadia/TerminalSettingsEditor/EnumEntry.idl @@ -8,4 +8,11 @@ namespace Microsoft.Terminal.Settings.Editor String EnumName { get; }; IInspectable EnumValue { get; }; } + + [default_interface] runtimeclass FlagEntry : Windows.UI.Xaml.Data.INotifyPropertyChanged, Windows.Foundation.IStringable + { + String FlagName { get; }; + IInspectable FlagValue { get; }; + Boolean IsSet; + } }