Skip to content

The popup system

Context menus shown when a player clicks or hold-clicks an object in the 2D/3D views.

Overview

Popups work like a mini comms tree. When a player clicks or hold-clicks in the science, comms, comms2d, or weapons view, the engine fires an event that creates a PopupPromise. The promise walks a route tree rooted at //popup/<console> (e.g. //popup/science) and displays the available buttons as a hold-menu on the client.

Each button in the route leads to a sub-path, just like comms. Use popup_navigate from within a popup handler to programmatically change which buttons are shown.

Three ids, and which one you want

Three variables are set when the popup fires - SCIENCE_ORIGIN_ID, SCIENCE_SELECTED_ID and SCIENCE_POPUP_ID, or the equivalent COMMS_*/WEAPONS_* variants. They are not interchangeable, and reaching for the wrong one is the single most common popup bug:

Variable What it is
<CONSOLE>_ORIGIN_ID The ship the client is flying.
<CONSOLE>_SELECTED_ID The console's standing selection - whatever it had targeted before the hold. 0 when it has none.
<CONSOLE>_POPUP_ID The object under the cursor when the player held. 0 for a hold on empty space (<CONSOLE>_POPUP_POINT then carries the point).

A menu that acts on the object the player clicked wants POPUP_ID. Gated on SELECTED_ID instead, it silently acts on the console's target rather than on what was clicked, and offers nothing at all when nothing is selected - which reads as a menu that only works sometimes. SELECTED_ID is right only when the selection is genuinely part of the interaction, as in "give THIS ship (selected) an order about THAT object (popup)".

There is one PopupPromise per (origin, selection) pair, and POPUP_ID changes with each hold - so one promise serves however many objects the player holds on while the selection stays put.

Quick example

//popup/science
* "Scan"
    signal_emit("scan_object", {"TARGET_ID": SCIENCE_SELECTED_ID})
* "Attack"
    target(ship_id, SCIENCE_SELECTED_ID)
from sbs_utils.procedural.popup import popup_navigate

# Redirect to a different set of buttons inside a popup handler
popup_navigate("popup/science/follow_up")

Console popup routes

Route Triggers on
//popup/science Science hold-click
//popup/comms Comms hold-click
//popup/comms2d 2D comms hold-click
//popup/weapons Weapons hold-click

API

PopupPromise

Bases: ButtonPromise

collect()

Garbage Collect the popup promise. Returns: bool: Was the GC successfully completed?

handle_button_sub_task(sub_task)

Add the sub task to the gui task Args: sub_task (MastAsyncTask): The task to add

leave()

Leave and remove the promise.

message(event)

Triggered when a button is pressed. Args: event (event): The button press event.

poll()

Get the result of the popup. Returns: PollResults: The result.

pressed_set_values(task)

When the popup is pressed, the task variables are set. Args: task (MastAsyncTask): The task.

selected(event)

Triggered when an object is selected on the widget. Args: event (event): The selection event

set_variables(event)

Set the variables based on the event that fired. Args: event (event): The event

show_buttons()

Display the popup menu buttons.

popup_navigate(path)

Set the active path for the current popup, similar to a comms route (e.g. //popup/science).

Parameters:

Name Type Description Default
path str

The new popup path to navigate to.

required

start_popup_selected(event)

Start or resume a popup for the given selection event.

Creates a new PopupPromise for the (origin, selected) pair if one does not already exist; otherwise resumes the existing promise. Called automatically by ConsoleDispatcher for science_popup, comms_popup, comms2d_popup, and weapons_popup events.

Parameters:

Name Type Description Default
event

The engine selection event that triggered the popup.

required

Returns:

Name Type Description
PopupPromise

The promise managing this popup, or None if the origin object no longer exists.