Skip to content

Add a confirmation popup

Designer · 20 min · No code

Result: a Yes/No question drawn over your own menu screen, with the screen still visible behind a dimmed scrim. Yes runs your work once. No or Back closes only the popup, and the cursor returns to the button you were on.

Before you start

How popups work in XenoCore

A XenoCore popup is not Lyra's full-screen dialog. It is a small activatable widget pushed into a stack inside the screen that asks, named OverlayStack. The screen stays drawn underneath, and the popup's scrim dims it.

The shipped popup is UserInterface/W_XenoCore_ConfirmPopup (its parent class is XenoCoreConfirmPopupBase). It already does the parts that are easy to get wrong:

  • It handles Back, and Back means No, so Back never falls through and closes your screen.
  • It sets its own input mode and starts the cursor on Yes, or on No when you ask it to.
  • It has a title, a question, and an optional red warning line that collapses when empty.

The Ask Confirm node shows it and continues on exactly one of two pins, On Yes or On No, once, after the popup has closed.

Steps

1. Give your screen an overlay stack

  1. Open W_Bestiary and switch to the Designer tab.
  2. If your root content is not already an Overlay, right-click it in the Hierarchy and choose Wrap With… › Overlay.
  3. From the Palette, drag a Common Activatable Widget Stack onto that overlay as its last child, so it draws on top.
  4. Rename it OverlayStack and tick Is Variable at the top of the Details panel.
  5. In its Slot settings, set Horizontal Alignment and Vertical Alignment to Fill.
  6. Set its Visibility to Self Hit Test Invisible, so it never blocks clicks when it is empty.

2. Ask

In W_Bestiary's Graph, where you want to ask (for example the click of a "Forget entry" button):

  1. Store the widget the cursor is on, such as the clicked button, in a variable ReturnFocus (a Widget object reference).
  2. Add Ask Confirm (category XenoCore › Confirm) and set:
    • Stack: drag in Get OverlayStack.
    • Popup Class: W_XenoCore_ConfirmPopup.
    • Title: Forget entry.
    • Question: Remove this creature from the bestiary?
    • Expand the node's advanced pins for Warning (This cannot be undone.) and Focus Cancel (tick it for a question whose Yes cannot be undone, so a stray press answers No).
  3. From On Yes, do the work.
  4. From both On Yes and On No, call Set Focus on ReturnFocus.
  5. Compile and Save.

Nothing needs binding or unbinding: each Ask Confirm is its own node instance and fires once.

No also covers the unexpected

On No fires for No, for Back, when the popup is closed from outside while still asking (the screen under it closed), and when the popup cannot be shown at all (no stack, or no class; the Output Log says "Ask Confirm: no popup to ask with"). So a graph waiting on the answer is never left hanging.

3. Optional: your own popup look

Duplicate W_XenoCore_ConfirmPopup into MyGame/UI and restyle it. Keep its parent class and these widget names, which the parent class looks for:

Widget Type Required
ConfirmButton, CancelButton CommonUI buttons Yes: the popup will not compile without them
TitleText, MessageText, WarningText Text blocks Optional

Make the text blocks Hit Test Invisible, then set Popup Class on the node to your copy.

Asking twice with one popup

Ask Confirm (Existing Popup) asks with a popup that is already on screen instead of pushing a new one. A new question replaces an open one, and the old one answers No.

For programmers: asking from a C++ screen

A C++ screen uses the same popup:

  • Give the screen a UCommonActivatableWidgetStack bound as OverlayStack and a TSubclassOf<UXenoCoreConfirmPopupBase> property set to W_XenoCore_ConfirmPopup on the Blueprint. Don't name the path in C++.
  • Push it with OverlayStack->AddWidget<UXenoCoreConfirmPopupBase>(PopupClass), bind the popup's OnDeactivated() to restore focus (call RemoveAll(this) first, because the popup is pooled), then call one of:
    • AskWithAnswer(Title, Question, Warning, bFocusCancel, [this](bool bConfirmed){ ... }), which reports both answers, once, after the popup has closed;
    • Ask(Title, Question, Warning, bFocusCancel, [this]{ ... }), which calls back on Yes only.
  • Is Asking (also Blueprint-callable) is true while a question is open; the save screen uses it to ignore its own keys meanwhile.
  • UXenoCoreSaveScreenBase is the worked example. See Add a mechanic by subclassing for setting up a C++ module.

Other screen helpers you can call from Blueprint

A Blueprint screen or HUD widget built on the XenoCore bases can also call these nodes:

Node On What it does
Set Shown Immediate Any HUD plate (XenoCoreHudPlateBase) Show or hide at once, with no fade. Changes opacity only, so the plate keeps ticking
Set Show Delay Any HUD plate Hold the fade-in back this many seconds, to stagger a column of plates. Fade-out is never delayed
Collapse All Except Any HUD plate Collapse every widget in the plate except one and the panels above it
Begin Hidden, Skip Intro A HUD plate's own graph Start hidden (cancel the entrance, then hide), or just cancel the entrance. Call from Construct on a plate that decides its own visibility
Set Target Target plate (XenoCoreTargetPlateBase) Show an actor's name and level on the badge, or None to hide it
Focus Row, Get Focus Target Trade row (XenoCoreTradeRowBase) Put the cursor on the row's button; the button itself, which is what can hold focus
Get Focus Target Art row (XenoCoreArtRowBase) The same, for an Arts list row
Get Slot Index, Is Selectable Save row (XenoCoreSaveRowBase) Which slot the row stands for; false for the autosave row while saving, and for a file from a newer build while loading

Test it

  1. Play, open the menu, open Bestiary, and click the button that asks.
  2. The popup appears over the screen; the screen is dimmed but visible. With Focus Cancel ticked, the cursor is on No.
  3. Press B (keyboard Escape). Only the popup closes, and the cursor is back on the button.
  4. Ask again and choose Yes. The work runs once.
  5. Ask a third time and choose No. Nothing runs.

If it doesn't work

Fails silently: the cursor is lost after the popup closes

Nothing hands focus back automatically, and nothing is logged. Call Set Focus on the stored widget from both pins.

Symptom Fix
The popup covers the whole screen and the screen behind vanishes You pushed it onto UI.Layer.Menu instead of OverlayStack. A layer shows only its top widget, so the popup replaced your screen. Give Ask Confirm the screen's own stack.
On No fires immediately and no popup appears Stack or Popup Class is empty. The Output Log says "Ask Confirm: no popup to ask with".
Back closes my screen as well You are using a popup of your own that is not a child of XenoCoreConfirmPopupBase. Such a popup must tick Is Back Handler in its Class Defaults, or Back falls through to the screen under it, which closes and takes the popup with it.
The popup asset will not compile It is missing ConfirmButton or CancelButton, or they are not CommonUI buttons. See step 3.

Going further