2021-10-06 13:33:05 +02:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
2021-02-24 00:37:23 +01:00
|
|
|
// Licensed under the MIT license.
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "Actions.h"
|
|
|
|
#include "Actions.g.cpp"
|
2021-05-18 23:37:16 +02:00
|
|
|
#include "KeyBindingViewModel.g.cpp"
|
2021-02-24 00:37:23 +01:00
|
|
|
#include "ActionsPageNavigationState.g.cpp"
|
2021-05-18 23:37:16 +02:00
|
|
|
#include "LibraryResources.h"
|
2021-07-03 00:35:55 +02:00
|
|
|
#include "../TerminalSettingsModel/AllShortcutActions.h"
|
2021-02-24 00:37:23 +01:00
|
|
|
|
|
|
|
using namespace winrt::Windows::Foundation;
|
2021-05-18 23:37:16 +02:00
|
|
|
using namespace winrt::Windows::Foundation::Collections;
|
2021-02-24 00:37:23 +01:00
|
|
|
using namespace winrt::Windows::System;
|
|
|
|
using namespace winrt::Windows::UI::Core;
|
2021-05-18 23:37:16 +02:00
|
|
|
using namespace winrt::Windows::UI::Xaml;
|
|
|
|
using namespace winrt::Windows::UI::Xaml::Controls;
|
|
|
|
using namespace winrt::Windows::UI::Xaml::Data;
|
2021-02-24 00:37:23 +01:00
|
|
|
using namespace winrt::Windows::UI::Xaml::Navigation;
|
|
|
|
using namespace winrt::Microsoft::Terminal::Settings::Model;
|
|
|
|
|
|
|
|
namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
|
|
|
|
{
|
2021-07-08 01:43:40 +02:00
|
|
|
KeyBindingViewModel::KeyBindingViewModel(const Windows::Foundation::Collections::IObservableVector<hstring>& availableActions) :
|
|
|
|
KeyBindingViewModel(nullptr, availableActions.First().Current(), availableActions) {}
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
KeyBindingViewModel::KeyBindingViewModel(const Control::KeyChord& keys, const hstring& actionName, const IObservableVector<hstring>& availableActions) :
|
2021-07-17 00:11:55 +02:00
|
|
|
_CurrentKeys{ keys },
|
|
|
|
_KeyChordText{ KeyChordSerialization::ToString(keys) },
|
2021-07-03 00:35:55 +02:00
|
|
|
_CurrentAction{ actionName },
|
|
|
|
_ProposedAction{ box_value(actionName) },
|
|
|
|
_AvailableActions{ availableActions }
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
|
|
|
// 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.
|
|
|
|
PropertyChanged([this](auto&&, const PropertyChangedEventArgs& args) {
|
|
|
|
const auto viewModelProperty{ args.PropertyName() };
|
2021-07-17 00:11:55 +02:00
|
|
|
if (viewModelProperty == L"CurrentKeys")
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
2021-07-17 00:11:55 +02:00
|
|
|
_KeyChordText = KeyChordSerialization::ToString(_CurrentKeys);
|
2021-05-18 23:37:16 +02:00
|
|
|
_NotifyChanges(L"KeyChordText");
|
|
|
|
}
|
|
|
|
else if (viewModelProperty == L"IsContainerFocused" ||
|
|
|
|
viewModelProperty == L"IsEditButtonFocused" ||
|
|
|
|
viewModelProperty == L"IsHovered" ||
|
|
|
|
viewModelProperty == L"IsAutomationPeerAttached" ||
|
|
|
|
viewModelProperty == L"IsInEditMode")
|
|
|
|
{
|
|
|
|
_NotifyChanges(L"ShowEditButton");
|
|
|
|
}
|
2021-07-03 00:35:55 +02:00
|
|
|
else if (viewModelProperty == L"CurrentAction")
|
|
|
|
{
|
|
|
|
_NotifyChanges(L"Name");
|
|
|
|
}
|
2021-05-18 23:37:16 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
hstring KeyBindingViewModel::EditButtonName() const noexcept { return RS_(L"Actions_EditButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
|
|
|
|
hstring KeyBindingViewModel::CancelButtonName() const noexcept { return RS_(L"Actions_CancelButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
|
|
|
|
hstring KeyBindingViewModel::AcceptButtonName() const noexcept { return RS_(L"Actions_AcceptButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
|
|
|
|
hstring KeyBindingViewModel::DeleteButtonName() const noexcept { return RS_(L"Actions_DeleteButton/[using:Windows.UI.Xaml.Controls]ToolTipService/ToolTip"); }
|
|
|
|
|
|
|
|
bool KeyBindingViewModel::ShowEditButton() const noexcept
|
|
|
|
{
|
|
|
|
return (IsContainerFocused() || IsEditButtonFocused() || IsHovered() || IsAutomationPeerAttached()) && !IsInEditMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeyBindingViewModel::ToggleEditMode()
|
|
|
|
{
|
|
|
|
// toggle edit mode
|
|
|
|
IsInEditMode(!_IsInEditMode);
|
|
|
|
if (_IsInEditMode)
|
|
|
|
{
|
|
|
|
// if we're in edit mode,
|
2021-07-03 00:35:55 +02:00
|
|
|
// - pre-populate the text box with the current keys
|
|
|
|
// - reset the combo box with the current action
|
2021-07-17 00:11:55 +02:00
|
|
|
ProposedKeys(_CurrentKeys);
|
|
|
|
ProposedAction(box_value(_CurrentAction));
|
2021-05-18 23:37:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeyBindingViewModel::AttemptAcceptChanges()
|
|
|
|
{
|
|
|
|
AttemptAcceptChanges(_ProposedKeys);
|
|
|
|
}
|
|
|
|
|
2021-07-17 00:11:55 +02:00
|
|
|
void KeyBindingViewModel::AttemptAcceptChanges(const Control::KeyChord newKeys)
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
2021-07-17 00:11:55 +02:00
|
|
|
const auto args{ make_self<ModifyKeyBindingEventArgs>(_CurrentKeys, // OldKeys
|
|
|
|
newKeys, // NewKeys
|
|
|
|
_IsNewlyAdded ? hstring{} : _CurrentAction, // OldAction
|
|
|
|
unbox_value<hstring>(_ProposedAction)) }; // NewAction
|
|
|
|
_ModifyKeyBindingRequestedHandlers(*this, *args);
|
2021-07-08 01:43:40 +02:00
|
|
|
}
|
2021-07-03 00:35:55 +02:00
|
|
|
|
2021-07-08 01:43:40 +02:00
|
|
|
void KeyBindingViewModel::CancelChanges()
|
|
|
|
{
|
|
|
|
if (_IsNewlyAdded)
|
|
|
|
{
|
|
|
|
_DeleteNewlyAddedKeyBindingHandlers(*this, nullptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ToggleEditMode();
|
|
|
|
}
|
2021-05-18 23:37:16 +02:00
|
|
|
}
|
|
|
|
|
2021-02-24 00:37:23 +01:00
|
|
|
Actions::Actions()
|
|
|
|
{
|
|
|
|
InitializeComponent();
|
2021-07-08 01:43:40 +02:00
|
|
|
|
|
|
|
Automation::AutomationProperties::SetName(AddNewButton(), RS_(L"Actions_AddNewTextBlock/Text"));
|
2021-05-18 23:37:16 +02:00
|
|
|
}
|
2021-02-24 00:37:23 +01:00
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
Automation::Peers::AutomationPeer Actions::OnCreateAutomationPeer()
|
|
|
|
{
|
2021-06-04 00:49:44 +02:00
|
|
|
_AutomationPeerAttached = true;
|
2021-05-18 23:37:16 +02:00
|
|
|
for (const auto& kbdVM : _KeyBindingList)
|
|
|
|
{
|
|
|
|
// To create a more accessible experience, we want the "edit" buttons to _always_
|
|
|
|
// appear when a screen reader is attached. This ensures that the edit buttons are
|
|
|
|
// accessible via the UIA tree.
|
|
|
|
get_self<KeyBindingViewModel>(kbdVM)->IsAutomationPeerAttached(_AutomationPeerAttached);
|
|
|
|
}
|
|
|
|
return nullptr;
|
2021-02-24 00:37:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actions::OnNavigatedTo(const NavigationEventArgs& e)
|
|
|
|
{
|
|
|
|
_State = e.Parameter().as<Editor::ActionsPageNavigationState>();
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
// Populate AvailableActionAndArgs
|
|
|
|
_AvailableActionMap = single_threaded_map<hstring, Model::ActionAndArgs>();
|
|
|
|
std::vector<hstring> availableActionAndArgs;
|
|
|
|
for (const auto& [name, actionAndArgs] : _State.Settings().ActionMap().AvailableActions())
|
|
|
|
{
|
|
|
|
availableActionAndArgs.push_back(name);
|
|
|
|
_AvailableActionMap.Insert(name, actionAndArgs);
|
|
|
|
}
|
|
|
|
std::sort(begin(availableActionAndArgs), end(availableActionAndArgs));
|
|
|
|
_AvailableActionAndArgs = single_threaded_observable_vector(std::move(availableActionAndArgs));
|
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
// Convert the key bindings from our settings into a view model representation
|
|
|
|
const auto& keyBindingMap{ _State.Settings().ActionMap().KeyBindings() };
|
|
|
|
std::vector<Editor::KeyBindingViewModel> keyBindingList;
|
|
|
|
keyBindingList.reserve(keyBindingMap.Size());
|
|
|
|
for (const auto& [keys, cmd] : keyBindingMap)
|
|
|
|
{
|
2021-07-03 00:35:55 +02:00
|
|
|
// convert the cmd into a KeyBindingViewModel
|
|
|
|
auto container{ make_self<KeyBindingViewModel>(keys, cmd.Name(), _AvailableActionAndArgs) };
|
2021-07-08 01:43:40 +02:00
|
|
|
_RegisterEvents(container);
|
2021-05-18 23:37:16 +02:00
|
|
|
keyBindingList.push_back(*container);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(begin(keyBindingList), end(keyBindingList), KeyBindingViewModelComparator{});
|
|
|
|
_KeyBindingList = single_threaded_observable_vector(std::move(keyBindingList));
|
|
|
|
}
|
|
|
|
|
2021-07-08 01:43:40 +02:00
|
|
|
void Actions::AddNew_Click(const IInspectable& /*sender*/, const RoutedEventArgs& /*eventArgs*/)
|
|
|
|
{
|
|
|
|
// Create the new key binding and register all of the event handlers.
|
|
|
|
auto kbdVM{ make_self<KeyBindingViewModel>(_AvailableActionAndArgs) };
|
|
|
|
_RegisterEvents(kbdVM);
|
|
|
|
kbdVM->DeleteNewlyAddedKeyBinding({ this, &Actions::_ViewModelDeleteNewlyAddedKeyBindingHandler });
|
|
|
|
|
|
|
|
// Manually add the editing background. This needs to be done in Actions not the view model.
|
|
|
|
// We also have to do this manually because it hasn't been added to the list yet.
|
|
|
|
kbdVM->IsInEditMode(true);
|
|
|
|
const auto& containerBackground{ Resources().Lookup(box_value(L"ActionContainerBackgroundEditing")).as<Windows::UI::Xaml::Media::Brush>() };
|
|
|
|
kbdVM->ContainerBackground(containerBackground);
|
|
|
|
|
|
|
|
// IMPORTANT: do this _after_ setting IsInEditMode. Otherwise, it'll get deleted immediately
|
|
|
|
// by the PropertyChangedHandler below (where we delete any IsNewlyAdded items)
|
|
|
|
kbdVM->IsNewlyAdded(true);
|
|
|
|
_KeyBindingList.InsertAt(0, *kbdVM);
|
|
|
|
}
|
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
void Actions::_ViewModelPropertyChangedHandler(const IInspectable& sender, const Windows::UI::Xaml::Data::PropertyChangedEventArgs& args)
|
|
|
|
{
|
|
|
|
const auto senderVM{ sender.as<Editor::KeyBindingViewModel>() };
|
|
|
|
const auto propertyName{ args.PropertyName() };
|
|
|
|
if (propertyName == L"IsInEditMode")
|
2021-02-24 00:37:23 +01:00
|
|
|
{
|
2021-05-18 23:37:16 +02:00
|
|
|
if (senderVM.IsInEditMode())
|
2021-02-24 00:37:23 +01:00
|
|
|
{
|
2021-05-18 23:37:16 +02:00
|
|
|
// Ensure that...
|
|
|
|
// 1. we move focus to the edit mode controls
|
2021-07-08 01:43:40 +02:00
|
|
|
// 2. any actions that were newly added are removed
|
|
|
|
// 3. this is the only entry that is in edit mode
|
|
|
|
for (int32_t i = _KeyBindingList.Size() - 1; i >= 0; --i)
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
|
|
|
const auto& kbdVM{ _KeyBindingList.GetAt(i) };
|
|
|
|
if (senderVM == kbdVM)
|
|
|
|
{
|
|
|
|
// This is the view model entry that went into edit mode.
|
|
|
|
// Move focus to the edit mode controls by
|
|
|
|
// extracting the list view item container.
|
|
|
|
const auto& container{ KeyBindingsListView().ContainerFromIndex(i).try_as<ListViewItem>() };
|
|
|
|
container.Focus(FocusState::Programmatic);
|
|
|
|
}
|
2021-07-08 01:43:40 +02:00
|
|
|
else if (kbdVM.IsNewlyAdded())
|
|
|
|
{
|
|
|
|
// Remove any actions that were newly added
|
|
|
|
_KeyBindingList.RemoveAt(i);
|
|
|
|
}
|
2021-05-18 23:37:16 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Exit edit mode for all other containers
|
|
|
|
get_self<KeyBindingViewModel>(kbdVM)->DisableEditMode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 00:49:44 +02:00
|
|
|
const auto& containerBackground{ Resources().Lookup(box_value(L"ActionContainerBackgroundEditing")).as<Windows::UI::Xaml::Media::Brush>() };
|
2021-05-18 23:37:16 +02:00
|
|
|
get_self<KeyBindingViewModel>(senderVM)->ContainerBackground(containerBackground);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Focus on the list view item
|
|
|
|
KeyBindingsListView().ContainerFromItem(senderVM).as<Controls::Control>().Focus(FocusState::Programmatic);
|
|
|
|
|
2021-06-04 00:49:44 +02:00
|
|
|
const auto& containerBackground{ Resources().Lookup(box_value(L"ActionContainerBackground")).as<Windows::UI::Xaml::Media::Brush>() };
|
2021-05-18 23:37:16 +02:00
|
|
|
get_self<KeyBindingViewModel>(senderVM)->ContainerBackground(containerBackground);
|
2021-02-24 00:37:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 00:49:44 +02:00
|
|
|
void Actions::_ViewModelDeleteKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const Control::KeyChord& keys)
|
2021-02-24 00:37:23 +01:00
|
|
|
{
|
2021-05-18 23:37:16 +02:00
|
|
|
// Update the settings model
|
|
|
|
_State.Settings().ActionMap().DeleteKeyBinding(keys);
|
|
|
|
|
|
|
|
// Find the current container in our list and remove it.
|
|
|
|
// This is much faster than rebuilding the entire ActionMap.
|
2021-06-04 00:49:44 +02:00
|
|
|
uint32_t index;
|
|
|
|
if (_KeyBindingList.IndexOf(senderVM, index))
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
2021-06-04 00:49:44 +02:00
|
|
|
_KeyBindingList.RemoveAt(index);
|
2021-05-18 23:37:16 +02:00
|
|
|
|
|
|
|
// Focus the new item at this index
|
|
|
|
if (_KeyBindingList.Size() != 0)
|
|
|
|
{
|
2021-06-04 00:49:44 +02:00
|
|
|
const auto newFocusedIndex{ std::clamp(index, 0u, _KeyBindingList.Size() - 1) };
|
2021-05-18 23:37:16 +02:00
|
|
|
KeyBindingsListView().ContainerFromIndex(newFocusedIndex).as<Controls::Control>().Focus(FocusState::Programmatic);
|
|
|
|
}
|
|
|
|
}
|
2021-02-24 00:37:23 +01:00
|
|
|
}
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
void Actions::_ViewModelModifyKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const Editor::ModifyKeyBindingEventArgs& args)
|
2021-02-24 00:37:23 +01:00
|
|
|
{
|
2021-07-08 01:43:40 +02:00
|
|
|
const auto isNewAction{ !args.OldKeys() && args.OldActionName().empty() };
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
auto applyChangesToSettingsModel = [=]() {
|
|
|
|
// If the key chord was changed,
|
|
|
|
// update the settings model and view model appropriately
|
2021-07-08 01:43:40 +02:00
|
|
|
// NOTE: we still need to update the view model if we're working with a newly added action
|
|
|
|
if (isNewAction || args.OldKeys().Modifiers() != args.NewKeys().Modifiers() || args.OldKeys().Vkey() != args.NewKeys().Vkey())
|
2021-07-03 00:35:55 +02:00
|
|
|
{
|
2021-07-08 01:43:40 +02:00
|
|
|
if (!isNewAction)
|
|
|
|
{
|
|
|
|
// update settings model
|
|
|
|
_State.Settings().ActionMap().RebindKeys(args.OldKeys(), args.NewKeys());
|
|
|
|
}
|
2021-07-03 00:35:55 +02:00
|
|
|
|
|
|
|
// update view model
|
|
|
|
auto senderVMImpl{ get_self<KeyBindingViewModel>(senderVM) };
|
2021-07-17 00:11:55 +02:00
|
|
|
senderVMImpl->CurrentKeys(args.NewKeys());
|
2021-07-03 00:35:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the action was changed,
|
|
|
|
// update the settings model and view model appropriately
|
2021-07-08 01:43:40 +02:00
|
|
|
// NOTE: no need to check for "isNewAction" here. <empty_string> != <action name> already.
|
2021-07-03 00:35:55 +02:00
|
|
|
if (args.OldActionName() != args.NewActionName())
|
|
|
|
{
|
|
|
|
// convert the action's name into a view model.
|
|
|
|
const auto& newAction{ _AvailableActionMap.Lookup(args.NewActionName()) };
|
|
|
|
|
|
|
|
// update settings model
|
|
|
|
_State.Settings().ActionMap().RegisterKeyBinding(args.NewKeys(), newAction);
|
|
|
|
|
|
|
|
// update view model
|
|
|
|
auto senderVMImpl{ get_self<KeyBindingViewModel>(senderVM) };
|
|
|
|
senderVMImpl->CurrentAction(args.NewActionName());
|
2021-07-08 01:43:40 +02:00
|
|
|
senderVMImpl->IsNewlyAdded(false);
|
2021-07-03 00:35:55 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Check for this special case:
|
|
|
|
// we're changing the key chord,
|
|
|
|
// but the new key chord is already in use
|
2021-07-08 01:43:40 +02:00
|
|
|
if (isNewAction || args.OldKeys().Modifiers() != args.NewKeys().Modifiers() || args.OldKeys().Vkey() != args.NewKeys().Vkey())
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
|
|
|
const auto& conflictingCmd{ _State.Settings().ActionMap().GetActionByKeyChord(args.NewKeys()) };
|
|
|
|
if (conflictingCmd)
|
|
|
|
{
|
|
|
|
// We're about to overwrite another key chord.
|
|
|
|
// Display a confirmation dialog.
|
|
|
|
TextBlock errorMessageTB{};
|
|
|
|
errorMessageTB.Text(RS_(L"Actions_RenameConflictConfirmationMessage"));
|
|
|
|
|
|
|
|
const auto conflictingCmdName{ conflictingCmd.Name() };
|
|
|
|
TextBlock conflictingCommandNameTB{};
|
|
|
|
conflictingCommandNameTB.Text(fmt::format(L"\"{}\"", conflictingCmdName.empty() ? RS_(L"Actions_UnnamedCommandName") : conflictingCmdName));
|
|
|
|
conflictingCommandNameTB.FontStyle(Windows::UI::Text::FontStyle::Italic);
|
|
|
|
|
|
|
|
TextBlock confirmationQuestionTB{};
|
|
|
|
confirmationQuestionTB.Text(RS_(L"Actions_RenameConflictConfirmationQuestion"));
|
|
|
|
|
|
|
|
Button acceptBTN{};
|
|
|
|
acceptBTN.Content(box_value(RS_(L"Actions_RenameConflictConfirmationAcceptButton")));
|
|
|
|
acceptBTN.Click([=](auto&, auto&) {
|
|
|
|
// remove conflicting key binding from list view
|
|
|
|
const auto containerIndex{ _GetContainerIndexByKeyChord(args.NewKeys()) };
|
|
|
|
_KeyBindingList.RemoveAt(*containerIndex);
|
|
|
|
|
|
|
|
// remove flyout
|
|
|
|
senderVM.AcceptChangesFlyout().Hide();
|
|
|
|
senderVM.AcceptChangesFlyout(nullptr);
|
2021-02-24 00:37:23 +01:00
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
// update settings model and view model
|
2021-07-03 00:35:55 +02:00
|
|
|
applyChangesToSettingsModel();
|
2021-05-18 23:37:16 +02:00
|
|
|
senderVM.ToggleEditMode();
|
|
|
|
});
|
2021-02-24 00:37:23 +01:00
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
StackPanel flyoutStack{};
|
|
|
|
flyoutStack.Children().Append(errorMessageTB);
|
|
|
|
flyoutStack.Children().Append(conflictingCommandNameTB);
|
|
|
|
flyoutStack.Children().Append(confirmationQuestionTB);
|
|
|
|
flyoutStack.Children().Append(acceptBTN);
|
|
|
|
|
|
|
|
Flyout acceptChangesFlyout{};
|
|
|
|
acceptChangesFlyout.Content(flyoutStack);
|
|
|
|
senderVM.AcceptChangesFlyout(acceptChangesFlyout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-03 00:35:55 +02:00
|
|
|
// update settings model and view model
|
|
|
|
applyChangesToSettingsModel();
|
|
|
|
|
|
|
|
// We NEED to toggle the edit mode here,
|
|
|
|
// so that if nothing changed, we still exit
|
|
|
|
// edit mode.
|
2021-05-18 23:37:16 +02:00
|
|
|
senderVM.ToggleEditMode();
|
2021-02-24 00:37:23 +01:00
|
|
|
}
|
|
|
|
|
2021-07-08 01:43:40 +02:00
|
|
|
void Actions::_ViewModelDeleteNewlyAddedKeyBindingHandler(const Editor::KeyBindingViewModel& senderVM, const IInspectable& /*args*/)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < _KeyBindingList.Size(); ++i)
|
|
|
|
{
|
|
|
|
const auto& kbdVM{ _KeyBindingList.GetAt(i) };
|
|
|
|
if (kbdVM == senderVM)
|
|
|
|
{
|
|
|
|
_KeyBindingList.RemoveAt(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 23:37:16 +02:00
|
|
|
// Method Description:
|
|
|
|
// - performs a search on KeyBindingList by key chord.
|
|
|
|
// Arguments:
|
|
|
|
// - keys - the associated key chord of the command we're looking for
|
|
|
|
// Return Value:
|
|
|
|
// - the index of the view model referencing the command. If the command doesn't exist, nullopt
|
|
|
|
std::optional<uint32_t> Actions::_GetContainerIndexByKeyChord(const Control::KeyChord& keys)
|
|
|
|
{
|
|
|
|
for (uint32_t i = 0; i < _KeyBindingList.Size(); ++i)
|
|
|
|
{
|
|
|
|
const auto kbdVM{ get_self<KeyBindingViewModel>(_KeyBindingList.GetAt(i)) };
|
2021-07-17 00:11:55 +02:00
|
|
|
const auto& otherKeys{ kbdVM->CurrentKeys() };
|
2021-10-06 13:33:05 +02:00
|
|
|
if (otherKeys && keys.Modifiers() == otherKeys.Modifiers() && keys.Vkey() == otherKeys.Vkey())
|
2021-05-18 23:37:16 +02:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO GH #6900:
|
|
|
|
// an expedited search can be done if we use cmd.Name()
|
|
|
|
// to quickly search through the sorted list.
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2021-07-08 01:43:40 +02:00
|
|
|
|
|
|
|
void Actions::_RegisterEvents(com_ptr<KeyBindingViewModel>& kbdVM)
|
|
|
|
{
|
|
|
|
kbdVM->PropertyChanged({ this, &Actions::_ViewModelPropertyChangedHandler });
|
|
|
|
kbdVM->DeleteKeyBindingRequested({ this, &Actions::_ViewModelDeleteKeyBindingHandler });
|
|
|
|
kbdVM->ModifyKeyBindingRequested({ this, &Actions::_ViewModelModifyKeyBindingHandler });
|
|
|
|
kbdVM->IsAutomationPeerAttached(_AutomationPeerAttached);
|
|
|
|
}
|
2021-02-24 00:37:23 +01:00
|
|
|
}
|