Skip to content

Custom Controls

Building Controls

Custom controls are built by composing drawables into reusable components using M2Panel as a base class. Once created, a custom control behaves like any other drawable - it can be added to screens, panels, or nested inside other custom controls. This enables a high-level, modular UI architecture where complex interfaces are assembled from self-contained, reusable building blocks.

Drawable Building Blocks

Drawable Description
M2Text Single-line text with font, scale, alignment, and trim
M2RectFilled Filled rectangle (solid color or gradient)
M2RectOutline Rectangle outline with stroke
M2Image Displays an uploaded M2ImageResource
M2Texture Off-screen render target
M2EllipseFilled / M2EllipseOutline Circle and ellipse variants
M2Arc Arc segment with start/end angles
M2Line Single line segment
M2Path Multi-point polyline
M2Triangles / M2Strip / M2Fan 2D geometry primitives
M2SpriteImage Sprite-sheet animation

Container Patterns

M2Panel

M2Panel is a container for grouping child drawables. Use it to create bounded UI regions. Both M2Panel and M2ArPanel support hardware clipping via clip(true), which clips child content to the panel's bounds.

val panel = M2Panel("status-bar")
panel.setX(0f).setY(0f)
panel.setWidthHeight(640f, 50f)

val label = M2Text()
label.setFont(M2FontResource.fontSmall)
    .setText("Status: Connected")
    .setX(10f).setY(25f)

panel.add(label)
screen.add(panel)

Composing a Control

Custom controls should build their child drawables in onCreate(), which is called when the control's owning screen becomes active. This ensures the drawable tree is constructed in the correct lifecycle stage.

class StatusBadge(private val text: String, private val color: M2Color) : M2Panel("badge") {
    private val bg = M2RectFilled()
    private val label = M2Text()

    init {
        setWidthHeight(120f, 36f)
    }

    override fun onCreate() {
        super.onCreate()

        bg.setWidthHeight(120f, 36f)
            .setColor(color)
        add(bg)

        label.setFont(M2FontResource.fontSmall)
            .setText(text)
            .setAlign(Align.CenterHorizontal)
            .setX(60f).setY(18f)
            .setColor(M2Color.White)
        add(label)
    }

    fun updateText(newText: String) {
        label.setText(newText)
    }
}

Built-In Controls

The SDK includes higher-level controls for common patterns:

Control Description
M2MultiLineText Wrapping multi-line text
M2TextTicker Scrolling / animated text ticker
M2Loading / M2Spinner Loading and activity indicators
M2ArSpinner AR-space loading indicator
M2GazeIndicator Eye tracking visual feedback

See Also