EM_Task/UnrealEd/Public/SListViewSelectorDropdownMenu.h
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

86 lines
3.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "InputCoreTypes.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Input/Events.h"
#include "Input/Reply.h"
#include "Widgets/SCompoundWidget.h"
#include "Widgets/Views/STableRow.h"
#include "Widgets/Input/SSearchBox.h"
/** This is a container widget to help refocus to a listview widget from a searchbox or other text box widgets that are used in conjunction.
Will refocus when the up or down arrows are pressed, and will commit a selection when enter is pressed regardless of where focus is. */
template <typename ListType>
class SListViewSelectorDropdownMenu: public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SListViewSelectorDropdownMenu)
{}
SLATE_DEFAULT_SLOT(FArguments, Content)
SLATE_END_ARGS()
public:
/**
* @param InDefaultfocusWidget The default widget to give focus to when the listview does not handle an action
* @param InTargetListView If the SListViewSelectorDropdownMenu is handling the KeyDown event, focus will be applied to the TargetListView for certain keys that it can handle
*/
void Construct(const FArguments& InArgs, TSharedPtr<SSearchBox> InDefaultFocusWidget, TSharedPtr<SListView<ListType>> InTargetListView)
{
check(InTargetListView.IsValid());
TargetListView = InTargetListView;
DefaultFocusWidget = InDefaultFocusWidget;
if (DefaultFocusWidget.IsValid())
{
// We have some overrides for OnKeyDown handling of the SSearchBox to provide the seamless functionality
InDefaultFocusWidget->SetOnKeyDownHandler(FOnKeyDown::CreateSP(this, &SListViewSelectorDropdownMenu<ListType>::OnKeyDown));
}
this->ChildSlot
[InArgs._Content.Widget];
}
// SWidget interface
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& KeyEvent) override
{
TSharedPtr<SListView<ListType>> TargetListViewPtr = TargetListView.Pin();
if (KeyEvent.GetKey() == EKeys::Up || KeyEvent.GetKey() == EKeys::Down)
{
// Deliver focus to the tree view, so the user can use the arrow keys to move through the items
return TargetListViewPtr->OnKeyDown(FindChildGeometry(MyGeometry, TargetListViewPtr.ToSharedRef()), KeyEvent);
}
else if (KeyEvent.GetKey() == EKeys::Enter)
{
// If there is anything selected, re-select it "direct" so that the menu will act upon the selection
if (TargetListViewPtr->GetNumItemsSelected() > 0)
{
TargetListViewPtr->SetSelection(TargetListViewPtr->GetSelectedItems()[0]);
}
return FReply::Handled();
}
else if (DefaultFocusWidget.IsValid())
{
TSharedPtr<SWidget> DefaultFocusWidgetPtr = DefaultFocusWidget.Pin();
FReply Reply = DefaultFocusWidgetPtr->OnKeyDown(FindChildGeometry(MyGeometry, TargetListViewPtr.ToSharedRef()), KeyEvent);
if (!DefaultFocusWidgetPtr->HasKeyboardFocus())
{
Reply.SetUserFocus(DefaultFocusWidgetPtr.ToSharedRef(), EFocusCause::OtherWidgetLostFocus);
}
return Reply;
}
return FReply::Unhandled();
}
// End of SWidget interface
private:
/** The type tree view widget this is handling keyboard input for */
TWeakPtr<SListView<ListType>> TargetListView;
/** Widget to revert focus back to when this widget does not handle (or forward) a key input */
TWeakPtr<SSearchBox> DefaultFocusWidget;
};