This page looks best with JavaScript enabled

Right-click Context Menu in Slate

 ·  ☕ 2 min read  ·  ✍️ Taylor

I’ve been doing lots of tool work lately, and a particular tool I’m working on right now uses a ListView. Each item in the ListView has specific context actions associated with them, and I really wanted them to appear in a right-click popup menu. So I did. And after this article you can, too. See how this works?

First off, you need to attach a function to your item widget’s .OnMouseButtonDown SLATE_EVENT.

1
2
3
4
5
6
7
void SMyCompoundWidget::Construct(const FArguments& InArgs)
{
   ChildSlot
   [
      SNew(SBorder)
      .OnMouseButtonDown(this, &SMyCompoundWidget::OnListViewItemClicked)
...

Then in the OnListViewItemClicked method, you need to filter out the PointerEvent param.

1
2
3
4
5
6
7
8
9
FReply SMyCompoundWidget::OnListViewItemClicked(const FGeometry& Geometry, const FPointerEvent& PointerEvent)
{
   if (PointerEvent.GetEffectingButton() == EKeys::RightMouseButton)
   {
      CreateContextMenu(PointerEvent.GetScreenSpacePosition());
      UE_LOG(LogTemp, Warning, TEXT("Right Clicked"));
   }
   return FReply::Unhandled();
}

Make sure to return FReply::Unhandled() from this method. Since we are attaching to this item widget’s mouse clicks, our parent ListView WILL NOT see any of the events if we return FReply::Handled(), which means you won’t be able to select items in the ListView. Returning FReply::Unhandled() ensures that the mouse click event is bubbled up.

Now we actually get to the context menu. It’s pretty straighforward. Create a MenuBuilder and start building.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void SMyCompoundWidget::CreateContextMenu(const FVector2D& mousePosition)
{
   constexpr bool closeAfterSelection = true;

   FMenuBuilder MenuBuilder(closeAfterSelection, nullptr);

   MenuBuilder.BeginSection("Test");
   {
      MenuBuilder.AddWidget(
         SNew(STextBlock)
         .Text(FText::FromString("Entry Actions")),
         FText(),
         true
         );

      MenuBuilder.AddMenuEntry(FText::FromString("Entry 0")),
         FText::FromString("This is the tooltip!"),
         FSlateIcon(FEditorStyle::GetStyleSetName(), "ContentBrowser.AssetActions.Delete"),
         FUIAction(FExecuteAction::CreateSP(this, &SMyCompoundWidget::EntryActionPressed)));
   }
   MenuBuilder.EndSection();

   FSlateApplication::Get().PushMenu(
      SharedThis(this),
      FWidgetPath(),
      MenuBuilder.MakeWidget(),
      mousePosition,
      FPopupTransitionEffect(FPopupTransitionEffect::ContextMenu));
}

Root around in FMenuBuilder because there’s a ton of stuff you can do. Create separators, submenus, stuff like that. That’s outside of the scope of this post, but have fun.

I’m sure there are other ways to do this, but this worked for me.

Share on