LogoLogo
What's new?StatusMSquared
  • Morpheus Platform Documentation
  • What is Morpheus Platform?
    • Glossary
    • Interoperability
    • Support
    • EULA
  • Firewall Problems
  • CREATION
    • Unreal Development
      • Get Started
        • Download the Editor
        • Upload Content
        • Creating your Own Map
        • Morpheus Base Project
        • Differences from Unreal
          • Character Configuration
        • Morpheus Networking
          • Introduction to Morpheus Networking
          • Network Levels
          • Replicated Properties
          • RPCs
          • Morpheus Render Targets
          • Morpheus Array
          • Networking FAQ
          • Replicating Sublevels
      • Editor Versions
      • Features & Guides
        • Example Plugin
          • Nameplates
          • In-Game Roles
          • Resizing
        • Actor Pooling
        • Audio
        • Avatars
          • Creating an Avatar
          • Attachments
            • MML Attachments
          • Custom Animation Variables
          • Importing an NFT Collection
          • Capsules and Mesh Transforms
        • Bots
        • Chat
          • Unreal Text Chat
        • Control Panels
          • Control Panel Configuration
          • DJ Booth Mission Control
          • Observer Controls
        • Crowd Audio
        • Crowd Rendering
          • Legacy Animated Crowd
            • Animated Crowd Console Commands
            • Attaching static meshes to crowd members
          • Crowd Materials
          • Performance Parameters
          • Live Config Settings
          • Crowd Animation
            • Crowd Anim Blueprint
              • User Guide - Crowd Anim Blueprint
              • Reference Guide - ABP Nodes
                • Animation Playback
                • States and State Machines
                • Variables
                • Transitions
                • Special
                • Blends
                • Additional Notes
        • Helpers & Extras
          • "Instanced Objects" in Blueprints
          • Objects with "world context"
          • Making DataAsset classes
          • Duplicate Objects
          • The Bootflow Subsystem
          • The "Wait For Condition" System
          • Advanced Graphics Settings
          • Listening to Inputs on UObjects
          • Morpheus UserID
          • World Services
          • M2Extras: Skins System
        • Loading Screen
        • Live Config
          • Editing for a World
          • Editing Locally
          • Default Settings
          • Accessing via Blueprint
          • Adding New Settings
          • Overriding Defaults
          • Using Arrays
        • MML
        • Motion Capture
        • Networking
        • Notifications
        • Raycastable Crowd
        • Singletons
        • Streaming & Multiplatform
          • GFN on Mobile
        • UI
          • "UI Mode"
        • User Collections
          • Creating a New Object Definition
          • Accessing from Unreal
            • Creating Objects Definitions
            • Transfer Objects
            • User Collection Views
            • Receiving Updates
        • Video Players
          • Embedded Video Player
          • Millicast video streaming
            • How to Setup an In-Game Video Stream
            • Picture-in-Picture mode
          • Streaming Video Player
            • How to Setup a URL Video Player
            • Picture-in-Picture mode
        • Visual Debugging
          • Inspector
        • Web UI
        • Online Services
          • KV Store Service
        • Web Requests
          • Http Requests
            • Legacy HTTP Nodes
          • JSON Handling
          • WebSockets
          • Identity Validation
          • Allowed External URLs
          • Walkthrough Example
            • Example Counter Service
        • World Travel
          • World Travel in the Editor
        • Avatar Physics Assets
        • Action Gameplay Helper Components
      • Workflows
        • Upgrade the Editor
        • Editing Project Settings
        • Profiling
        • Performance Guarantees
        • Marketplace Importing
        • Extra Workflows
          • Setup Play-in-Editor
          • Setup Local Asset Validation
          • Adding Gameplay Tags
          • Validating Game Assets
          • Custom Connection Modes
          • Connect Editor to a World
          • Common Issues
      • Best Practices
    • Worlds
      • Invite Players
        • Setting Role Groups
      • Persistent Worlds
      • Always on Worlds
    • Running Events
      • Large Scale Events - Checklist
      • Anti-Cheat (EAC)
      • Player Entry
        • React Native
        • Steam
        • Hardware Requirements
      • Broadcast
        • OBS Integration
      • Failover
      • Capacity and Queue Management
  • ADMINS
    • Access Control
      • Add Metaverse Contributors
      • Create a New Project
    • Pricing
      • Development Support
      • Included Usage & Overages
      • Cloud Streaming
      • Access Modes
      • War Room Support
      • Platform SLA
    • Settings
      • Projects
  • APIs and Tooling
    • API Reference
      • Accounts
      • Events
      • Key/Value Store
      • Organizations
      • Realtime
      • User Profile
      • World Builder
      • Worlds
    • Template Web App
      • Moderation
    • Pixel Streaming
    • Launcher
  • Integrations
    • Analytics
      • Send Events from Web
      • Send Events from Unreal
    • Chat
      • Integrate Pubnub with your Unreal Project
      • Add Moderation to Chat
Powered by GitBook
On this page
  • Overview
  • How to use standard button data
  • Adding a standard UI widget
  • Making a data object
  • Listening to and updating the standard data
  • Modifying standard buttons' visuals
  • What needs to be button data?
  • Standard button data types
  • M2_StandardButtonData (Widget type: WBP_M2_StandardButton)
  • M2_StandardButtonListData (Widget type: WBP_M2_StandardButtonList)
  • M2_StandardButtonGroupData (Widget type: WBP_M2_StandardButtonGroup)
  • BP_StandardTextBlockData (Widget type: WBP_M2_StandardTextBlock)
  • BP_StandardSliderButtonData (Widget type: WBP_M2_StandardButtonSlider)
  • BP_StandardInputTextButtonData (Widget type: WBP_M2_StandardButtonInputText)
  • M2_StandardButtonListWithScrollAndShortcutData (Widget type WBP_M2_StandardButtonListWithScrollAndShortcut)
  • Device Settings
  • Adding new data types
  • Widget themes

Was this helpful?

  1. CREATION
  2. Unreal Development
  3. Features & Guides
  4. UI

Standard/Data Driven UI

Last updated 8 months ago

Was this helpful?

Support for M2 Standard button will be ending soon. This system will remain usable for a while but MSquared advises that you implement your own widgets without the M2 Standard Button to avoid disruption.

Overview

We have a number of places in our codebase where we want simple data-driven widgets, displaying e.g. lists of buttons, options or sub-menus. To handle these, we’ve made a set of “standard button data” objects and widgets. By using these, we can automatically build simple widgets without needing to create bespoke widgets, for e.g. interaction or devices.

A "Standard UI widget" is comprised of two main parts: the button widget (extending M2_StandardButtonWidgetBase), which is the actual UI widget added to the screen, and the button data (extending M2_StandardButtonBaseData), which contains the data which can be used to build the button widget. That way, we can build and modify more complex sets of buttons at runtime by updating the data, without needing widgets to be added.

How to use standard button data

Adding a standard UI widget

You can add standard UI widgets directly in the designer, and fill out the details there if desired. E.g. adding a WBP_M2_StandardButtonList, or WBP_M2_StandardButton

In the Event Graph, you can then listen to the widget’s events, e.g. OnButtonClicked for the WBP_M2_StandardButton

Making a data object

Each standard UI widget has an expected button data type. Within that are a number of fields that define the appearance.

  • Every data object has the “common” fields - an Id (to search for/identify particular data objects), some Text, optional SubText, and icons. There are 4 possible icon locations: IconLeft1, IconLeft2, IconRight1 and IconRight2, which can be used to add a number of optional icons to different locations on the button.

  • Some data types have sub-lists of other data objects, such as buttons (M2_StandardButtonData) spawning sub-menus, or lists (M2_StandardButtonList) containing other widgets. In these cases, you can select the data type from a dropdown.

  • Data objects can also be created outside of the designer view, e.g.

    • Creating them dynamically at runtime

    • Making “instanced” data variables, of M2_StandardButtonDataBase or one of the more specific child classes. NOTE: You will need to make sure it has the Details->Advanced->Instanced box checked, so that you can create the subobject within your executo

Listening to and updating the standard data

  • Each data type has specific events relevant to its data, e.g. the BP_StandardInputTextButtonData having the OnTextCommitted event.

  • The data also has setters, which trigger the UI to refresh, for instance UpdateDetails, which updates the text and icon shared across all button data types, or UpdateList, which is exclusive to M2_StandardButtonListData, and can be used to modify the list of button data contained within the list

  • In some cases, a widget's available button data will be of the base button data class, so may not have the relevant fields. you will need to cast it to modify fields specific to particular types of button data.

Note that it is bad practice to directly modify the sub-widgets inside a standard button widget. If the field is represented by the widget's data, e.g. its text or icon, we should only modify it from its button data. Modifying the data via the relevant methods will trigger the widget to refresh. That way, the data and widget always match.

As of v21, we have an extra helper function GetWidgetButtonData, which should be used in favor of getting the widget's button data directly - this automatically converts the button data from M2_StandardButtonBaseData to the appropriate type for the widget, e.g. M2_StandardButttonData for WBP_M2_StandardButton, or M2_StandardButtonListData for WBP_M2_StandardButtonList.

Finding nested button data

  • To navigate a nested button data variable, some helper functions have been added:

    • FindStandardButtonByClass: Searches for the first button of the provided type within the button data.

    • FindStandardButtonById: Similar to the above, but allows us to search for a specific button data by Id

    • FindStandardButtonsByClass: Searches for all standard buttons of the provided class within the data. Optionally includes a “recursion depth”, in case we know how deep we should be looking inside the data (i.e. only looking for top-level buttons)

Modifying standard buttons' visuals

Via skins (Support ending)

If you want to change the appearance of buttons, such as the styling or color scheme, this can be handled through the skin. The BP_StandardButtonSkinSettings has various fields that control how the visuals look, such as the background color, the images used for check-boxes and buttons, and the location of the button's "shortcut icon". For more details on skins, see How to use skins

Via modifying the widget

If you want to modify a specific button type in more bespoke ways, you will need to customize the widgets themselves. If you have access to the widget, you can do this directly. If you don't (i.e. it is a base origin widget and you are a downstream project), you will need to replace the widget. For this, see Widget themes.

Some important points to note when working with standard UI widgets (extending M2_StandardButtonWidgetBase):

  • ButtonData is the default M2_StandardButtonBaseData type, so may not have all the fields you are expecting. You will need to cast to the correct data type.

  • Event Initialize From Data is the best place to respond to any changes in button data. is called when the widget is created (in-game and in design-time), and when the data is updated, so can be used to respond to changes, such as hiding parts of the widget that are no longer relevant, updating text, etc.

  • When making cosmetic changes, you should consider What needs to be button data? - some things could be achieved simply by adding extra variables to the base widget, others should be in data to be propagated effectively.

What needs to be button data?

If you are wanting to make visual changes to a standard UI widget, it's worth considering where the change should be made in the button data, or exclusively in the widget itself. Things to think about:

  • If the change is related to the function of the widget, e.g. the state of a check-box, that is needed to accurately represent the widget, it will need to be in button data.

  • If the change is purely cosmetic, you may be able to get away with making it a field in the widget, without having it in button data:

    • If you want the styling change to be global for all widgets of that type, you can put it in a variable (and add it to the skin, if you want it to be modifiable in different styles)

    • If you want it to be modifiable per-instance, the change may need to be data driven:

      • If you're only having the property configurable for "root" widgets, e.g. adding the WBP_M2_StandardButton directly to the UI, you could get away with making it an Instance Editable property in the widget BP.

      • If you want the property to be configurable for "non-root" widgets, e.g. in a widget entry inside a WBP_M2_StandardButtonList, it will need to be button data.

Standard button data types

M2_StandardButtonData (Widget type: WBP_M2_StandardButton)

The common button. Supports being either regular clickable buttons, toggle buttons, or “menu buttons”

  • The ButtonType can be either ActionButton, ToggleButton, MenuOnly or DisabledButtonWithSubmenu.

  • The SubMenuData can either be left blank, or you can add a M2_StandardButtonListData to it.

    • If a sub-menu is present, and the ButtonType is MenuOnly, clicking the button will open the sub-menu.

    • If a sub-menu is present, and the ButtonType is not MenuOnly, an extra button will be spawned to the side, to open the sub-menu.

    • If the ButtonType is MenuOnly and there is no sub-menu, the button will be treated as “disabled”.

    • DisabledButtonWithSubmenu is similar to MenuOnly, but forces the button to be treated as "disabled", but having an extra "menu button" to the side. This can be used for buttons where the text is more of an indication, rather than an actual button, and the sub-menu is optional extra details with less focus.

  • The standard button also contains shortcut data. For more details on this, see Keyboard Shortcuts in Standard Buttons

M2_StandardButtonListData (Widget type: WBP_M2_StandardButtonList)

Contains a ButtonList field, which can be filled with any form of standard button data.

M2_StandardButtonGroupData (Widget type: WBP_M2_StandardButtonGroup)

A group, specifically of M2_StandardButtonGroupEntryData (Widget type: WBP_M2_StandardGroupEntryButton). These are checkboxes, where clicking one can affect others in the group:

  • You can listen to entries in the group being selected or deselected, and can get any selected options.

  • If SingleSelection is false, you can select multiple options from the group. Otherwise, you can only click one (and clicking something else will deselect the current one)

BP_StandardTextBlockData (Widget type: WBP_M2_StandardTextBlock)

A text block, which has wrapping text.

BP_StandardSliderButtonData (Widget type: WBP_M2_StandardButtonSlider)

A basic slider. Has an OnValueUpdated event that is triggered when the value changes, and a UpdateValue method used to update the slider's current value

BP_StandardInputTextButtonData (Widget type: WBP_M2_StandardButtonInputText)

An "input field" widget, where you can enter text. Has UpdateCurrentText and CommitCurrentText methods, and OnTextUpdated and OnTextCommitted.

M2_StandardButtonListWithScrollAndShortcutData (Widget type WBP_M2_StandardButtonListWithScrollAndShortcut)

A modification of the standard button list, where there is a bespoke scrollbar widget, and a shortcut that tracks the selected button and can be used to click on it. Used by the interaction UI. Has added shortcut data fields to listen to scrolling up/down, and triggering the buttons

Entries in the list must be M2_StandardButtonWithScrollShortcutData (Widget type WBP_M2_StandardButtonWithScrollShortcut)

Device Settings

As well as the BP/M2 standard button data types, we also have some "device settings" as entries in the list of standard button data types. These are specializations of the M2_StandardButtonData, used by Inventory. For more details, see Device Settings.

Adding new data types

  • If you create a new class extending M2_StandardButtonBaseData, you can add fields, methods and events to it.

    • If you want to make changes that should update the UI, the recommended approach is to call BroadcastDataUpdated once the changes have been applied. This will retrigger the UI to refresh (calling InitializeFromData), so that it will reflect your updates.

    • NOTE: When making a button data class, consider What needs to be button data?

  • Then make a corresponding widget to represent this button data, using M2_StandardButtonWidgetBase as a base.

    • Make sure to specify your intended data as the RequiredButtonDataClass.

    • You can override its EventInitializeFromData to apply any additional data specific to your new button data type, casting the existing ButtonData to your correct data type

      • EventInitializeFromData is called when the widget is created (in-game and in design-time), and when the data is updated, so can be used to respond to changes, such as hiding parts of the widget that are no longer relevant, updating text, etc.

  • If you want your data type to be usable dynamically from e.g. a button list, you'll also need to add it to the visuals theme map. For more details, see Widget themes

Widget themes

You may have seen _Info widgets in Origin, e.g. WBP_M2_StandardButtonList_Info. These are an example of an alternative "theme" for the standard button data.

A standard UI "theme" is the mapping from button data to widgets. This is how we build the widgets from the data in e.g. a standard button list.

If there is not a specific class in the list, then the most relevant parent class will be used instead, e.g. BP_DeviceModule will be treated as a M2_StandardButtonData.

In a given button data widget, you can provide an override theme using the WidgetVisualsTheme variable. For lists, this theme will then be applied to all entries within the list.

This page is designed to be the starting point for potential users of data driven UI. Any questions, or any feature requests for the system, please reach out to !

Support for skinning is ending soon. Please see for details.

The following is a list of button data types in Origin currently, and their corresponding widgets. More data types can be added later. If you have suggestions, please reach out to !

https://docs.msquared.io/tutorials-and-features/ui/how-to-use-skins
Benjamin Naccarato
Benjamin Naccarato
An example WBP_M2_StandardButtonList added to a widget. The value of the widget’s ButtonData populates the widget’s entries.
WBP_M2_StandardButtonList acts as a list of "standard button data", in this case being two BP_StandardTextBlockData entries, being two blocks of basic text
Some example logic for making a list of buttons at runtime, adding listeners to when they are clicked, and updating a standard button list.
ButtonData is a M2_StandardButtonBaseData, which doesn't have shortcut info. If we want to update the WBP_M2_StandardButton's shortcut info, we'll need to cast the data to M2_StandardButtonData.
An example of updating the text and icon of a button widget. Note that we are getting the widget's button data, and updating that, rather than directly setting its text/icon subwidgets.
In the slider widget, we get the slider values from the data, and use them to update the slider widget's properties
The "Grant Gadget to Selected" button opens the submenu
The "Select People" button is disabled, but has a submenu. This is because the left mouse button isn't actually used to click the button - it is a hint on how to select people. The submenu is then additional options on how to select people.
The input
In the slider widget, we get the slider values from the data, and use them to update the slider widget's properties
DA_StandardButtonsDefaultTheme is the default mapping of button data to corresponding widgets.
WBP_DeviceControlsWidget uses the DA_StandardButtonsInfoTheme to replace the normal widges with _Info widgets