Selection Change Handler
Overview
This example demonstrates how to react to selection changes in the editor using RegisterOnSelectionChanged. This hook enables addons to update their UI, load relevant data, or perform actions when the user selects different objects in the scene or asset browser.
Files
package.json
{
"name": "Selection Monitor Addon",
"author": "Polyphase Examples",
"description": "Monitors and reacts to selection changes.",
"version": "1.0.0",
"tags": ["editor", "example"],
"native": {
"target": "editor",
"sourceDir": "Source",
"binaryName": "selectionmonitoraddon",
"apiVersion": 2
}
}
Source/SelectionMonitorAddon.cpp
#include "Plugins/PolyphasePluginAPI.h"
#include "Plugins/PolyphaseEngineAPI.h"
#if EDITOR
#include "Plugins/EditorUIHooks.h"
#include "imgui.h"
#endif
static PolyphaseEngineAPI* sEngineAPI = nullptr;
#if EDITOR
static int sSelectionChangeCount = 0;
/**
* @brief Called when the editor selection changes.
* @param userData User-provided data (unused in this example).
*
* This callback is invoked whenever:
* - The user selects/deselects objects in the scene
* - The user selects assets in the content browser
* - Selection is changed programmatically
* - Selection is cleared
*/
static void OnSelectionChanged(void* userData)
{
sSelectionChangeCount++;
sEngineAPI->LogDebug("Selection changed (#%d)", sSelectionChangeCount);
// Example: Query the new selection via the editor API
sEngineAPI->LogDebug("Loading properties for selected object...");
// Example: Update addon UI to reflect new selection
sEngineAPI->LogDebug("Refreshing custom inspector...");
}
/**
* @brief Draw callback for a custom top-level menu showing selection stats.
* @param userData User-provided data (unused in this example).
*/
static void DrawSelectionMenu(void* userData)
{
char label[64];
snprintf(label, sizeof(label), "Changes: %d", sSelectionChangeCount);
ImGui::MenuItem(label, nullptr, false, false);
ImGui::Separator();
if (ImGui::MenuItem("Reset Counter"))
{
sSelectionChangeCount = 0;
}
}
#endif
/**
* @brief Called when the plugin is loaded by the engine.
* @param api Pointer to the engine API.
* @return 0 on success, non-zero on failure.
*/
static int OnLoad(PolyphaseEngineAPI* api)
{
sEngineAPI = api;
api->LogDebug("Selection Monitor Addon loaded!");
return 0;
}
/**
* @brief Called when the plugin is about to be unloaded.
*/
static void OnUnload()
{
if (sEngineAPI) sEngineAPI->LogDebug("Selection Monitor Addon unloading.");
sEngineAPI = nullptr;
}
#if EDITOR
/**
* @brief Register editor UI hooks.
* @param hooks Pointer to the EditorUIHooks function table.
* @param hookId Unique identifier for this plugin's hooks.
*
* All hooks registered here are automatically cleaned up via
* RemoveAllHooks(hookId) when the plugin unloads.
*/
static void RegisterEditorUI(EditorUIHooks* hooks, uint64_t hookId)
{
hooks->RegisterOnSelectionChanged(hookId, OnSelectionChanged, nullptr);
hooks->AddTopLevelMenuItem(hookId, "Selection", DrawSelectionMenu, nullptr);
sEngineAPI->LogDebug("Selection change handler registered");
}
#endif
extern "C" OCTAVE_PLUGIN_API int PolyphasePlugin_GetDesc(PolyphasePluginDesc* desc)
{
desc->apiVersion = OCTAVE_PLUGIN_API_VERSION;
desc->pluginName = "Selection Monitor Addon";
desc->pluginVersion = "1.0.0";
desc->OnLoad = OnLoad;
desc->OnUnload = OnUnload;
desc->Tick = nullptr;
desc->TickEditor = nullptr;
desc->RegisterTypes = nullptr;
desc->RegisterScriptFuncs = nullptr;
#if EDITOR
desc->RegisterEditorUI = RegisterEditorUI;
#else
desc->RegisterEditorUI = nullptr;
#endif
desc->OnEditorPreInit = nullptr;
desc->OnEditorReady = nullptr;
return 0;
}
API Reference
RegisterOnSelectionChanged
void (*RegisterOnSelectionChanged)(HookId hookId, EventCallback cb, void* userData);
Registers a callback invoked when the editor selection changes.
Parameters:
- hookId - The hook identifier provided by RegisterEditorUI
- cb - Function to call when selection changes
- userData - Optional user data passed to the callback
Triggered when: - Objects are selected/deselected in the scene - Assets are selected in the content browser - Selection is modified programmatically - Selection is cleared
EventCallback
typedef void (*EventCallback)(void* userData);
Callback signature for parameterless events.
Parameters:
- userData - User-provided data from registration
Best Practices
- Query Selection - Use the editor API to get details about what is actually selected
- Performance - Keep callbacks fast, as they fire frequently during multi-select operations
- Deferred Updates - For expensive operations, defer work until the next frame
- Multi-Selection - Handle both single and multi-selection cases
- Empty Selection - Always handle the case where selection is cleared
- Automatic Cleanup - Hooks are cleaned up automatically; manual unregistration is not required
- State Sync - Keep addon state synchronized with editor selection