Search

Studio

Macro Argument Form and Runtime Dashboard: UI Builder

Design a macro argument form (.uibproj) and runtime dashboard (.uibrt) in the MAS UI Builder, export ui.xml and script_args.py, and drive widgets from Python.

  • Windows
  • Mac
  • Emulator
  • Cloud device
  • Studio
  • Python SDK
Intermediate Updated 10 min read
On this page
  1. The two project types
  2. Open the UI Builder from the Code Editor
  3. The editor at a glance
  4. The macro argument form (.uibproj)
  5. The 11 argument widgets
  6. Layout widgets
  7. Argument metadata
  8. Validation
  9. The action bar
  10. What the form exports
  11. Read the values in your script
  12. The native settings dialog on a device
  13. The runtime dashboard (.uibrt), driven from Python
  14. The 7 runtime widgets
  15. How updates reach the dashboard
  16. Checklists before you ship
  17. Layout tips

The UI Builder is the drag-and-drop designer that ships with Macro Automation Studio. It gives a Python macro two things a command line cannot: a typed argument form the user fills in before a run, and a live runtime dashboard that shows progress while the run happens. You place widgets on a canvas; MAS turns the form into Python arguments and turns the dashboard into one-line mas.ui.* calls. This page is for anyone who has a working script and wants to make it usable by other people.

The two project types

ProjectFileWhat it isWidgets
Argument form.uibprojThe window the user fills in before the macro runs11 argument widgets, 3 layout widgets, an action bar
Runtime dashboard.uibrtThe live panel shown while the macro runs7 runtime widgets

A macro can have one, the other, both, or neither. They are separate files in the project folder. Only the script itself, src/app.py, is required.

Open the UI Builder from the Code Editor

The UI Builder is a separate application that MAS launches for you. It is part of the standard install from the download page, so there is nothing extra to set up. You never start it by hand.

  1. Open your macro in the Code Editor.
  2. In the toolbar, click Add Args UI to design an argument form, or Add Runtime UI to design a dashboard.
  3. If the project has no such file yet, MAS creates script_runner.uibproj or runtime_ui.uibrt, saves it to the project, and then opens the UI Builder on it.
  4. Once a file exists, the same buttons read Edit Args UI and Edit Runtime UI.

The UI Builder runs as a single instance. If it is already open, clicking a button switches it to the file you asked for. When a .uibrt exists, the Code Editor’s bottom panel gains a runtime tab next to the console, with a refresh control that re-reads the file after you edit it.

The editor at a glance

  • Palette (left): every widget, grouped into argument, layout and runtime kinds. Drag one onto the canvas.
  • Canvas (center): a scale model of the window. Widgets have absolute pixel positions and sizes. A 10 pixel snap grid is on by default.
  • Tabs (above the canvas): a form can have several tabs. Dashboards can use tabs as well.
  • Inspector (right): every property of the selected widget, including its argument key or its runtime name.
  • Toolbar (top): the snap grid toggle, an auto-layout button for the active tab, Preview, Save and Save As.

Save always writes the project file. For an argument form it also exports ui.xml and src/script_args.py, but only when validation passes. If there are issues, the project is saved and the exports are skipped until you fix them.

The macro argument form (.uibproj)

An argument form is a window of input fields. Each field carries a key. At run time MAS turns every field into a --key=value argument that your script reads.

The 11 argument widgets

Each one produces exactly one argument.

WidgetKindValue in PythonUse for
Text Inputtext-inputstrnames, URLs, short free text
Text Areatext-areastrlong text, lists, pasted blocks; you set the rows
Number Inputnumber-inputint or floatcounts and thresholds, with min, max, step, precision and a suffix
Slidersliderint or floata bounded number chosen by dragging; can show its value
Checkboxcheckboxboolon or off flags
Combo Boxcomboboxone option’s strpick one from a list; can be editable
Radio Groupradio-groupone option’s strpick one when every option should be visible
File Pickerfile-pickerstr pathchoose a file, with optional filters such as *.txt;*.csv
Directory Pickerdirectory-pickerstr pathchoose a folder
Date Pickerdate-pickerstra date in the format you set, for example YYYY-MM-DD
Time Pickertime-pickerstra time as HH:mm, HH:mm:ss, hh:mm A or hh:mm:ss A

A Number Input or Slider becomes float when its step is not a whole number, otherwise int.

Layout widgets

These three add structure and produce no argument.

  • Label: static helper text with an optional font size.
  • Separator: a horizontal or vertical divider with an optional caption.
  • Group Box: a titled container that groups related fields.

Argument metadata

Every argument widget has a block of metadata in the Inspector.

  • key (required): the argument name. It must be a valid Python identifier (a letter or underscore, then letters, digits or underscores) and unique across the whole form.
  • required: the form will not run without a value, and the generated argument is marked required=True.
  • helpText: a short explanation that becomes the argument’s help string.
  • showLabel, labelPosition (top or left) and labelGap: control how the field’s label is drawn.

Validation

Before exporting, the UI Builder checks that every argument widget has a key, that each key is a valid identifier, and that no key is used twice. A project must also contain at least one tab. Fix every issue, then click Save again to export.

The action bar

Below the tabs sits the row of buttons that closes the window. New forms start with Cancel and Run. In the Inspector you can edit each button’s text, role (run, cancel, reset or custom) and style (primary, secondary or danger), and set the bar’s alignment to right, center, left or spread. For most macros the default is right.

What the form exports

  • src/script_args.py: generated argparse code, grouped by tab. It parses sys.argv on import. Never hand-edit it; it is rewritten on every Save.
  • ui.xml: the structural description Studio reads to render the native input dialog.

Read the values in your script

Each tab becomes a namespace. A tab’s name is lowercased and non-alphanumeric characters become underscores, so “My Settings” becomes my_settings. Access a value as args.<tab>.<key>.

python
import mas
from src.script_args import args

target = args.general.target_name    # Text Input, key "target_name"
rounds = args.general.rounds         # Number Input, key "rounds"
dry_run = args.advanced.dry_run      # Checkbox, key "dry_run"

for i in range(rounds):
    mas.log(f"round {i + 1} of {rounds}")
    if dry_run:
        continue
    match = mas.find_object_retry(1234, total_tries=3, time_sleep=2.0)
    if match:
        mas.click(match.x, match.y)

Combo Box and Radio Group values are restricted to their options with choices=[...]. A Checkbox uses action='store_true', so it is False unless ticked.

The native settings dialog on a device

Studio does not embed the UI Builder canvas at run time. It reads ui.xml and renders one native form, with the same tabs and fields, in two places:

  • In the Code Editor, when you click Run on a script that has arguments.
  • On a device card in Device Groups, behind the Macro settings button.

On a device card the values you enter are saved for that device, and a Profile bar at the top of the dialog lets you share one set of values across many devices. See Settings profiles. If a macro has no ui.xml, Studio falls back to reading the argparse definitions in script_args.py.

The runtime dashboard (.uibrt), driven from Python

A runtime dashboard is the live panel Studio shows while a macro runs. You design it in the UI Builder and drive it from your script with mas.ui.* calls. The dashboard appears in the Code Editor’s bottom panel and in the Dashboard view of the device card in Device Groups.

The one rule that connects everything is the widget name, set in the Inspector. That name is the first argument to every mas.ui.* call. A typo between the name in the file and the name in your code is the most common dashboard bug: the call simply updates nothing. Make each name a valid Python identifier, unique within the dashboard, and descriptive (status_label, items_chart).

The 7 runtime widgets

WidgetKindShows or doesDriven or read by
Labelruntime-labelone line of text with font size, color and alignmentset_text
Progress barruntime-progressa value between min and max, optional percentageset_progress, set_text for its label
Chartruntime-charta line, bar or pie chart that keeps up to maxDataPointsadd_data_point, set_chart_data, clear_chart
Text arearuntime-textareascrolling text or a log, sans or mono, optional line numbers and maxLinesappend_text, set_textarea, clear_text
Tableruntime-tablerows under fixed columns, optional maxRowsset_table_data, append_table_row, clear_table, cell_button
Buttonruntime-buttona clickable button in the default, outline or destructive stylewait_for_event, on_click
Inputruntime-inputa text field the user types intoget_input_value, on_change

The first five are display widgets: the script writes, the user reads. The last two are interactive: the user acts, the script reads.

How updates reach the dashboard

Every mas.ui.* call is one JSON-RPC message from your script to the MAS app. The app forwards it as an event keyed by the device, and the dashboard re-renders that widget. Text areas and tables keep a local mirror in the SDK so append_text and append_table_row can build on the previous content without asking the app. Wrap a multi-widget refresh in mas.ui.batch() so it travels as a single message; that is the difference between a smooth dashboard and one that flickers inside a tight loop. Batches cannot be nested.

python
import mas

steps = ["open_app", "collect", "claim"]
mas.ui.set_text("status", "Starting")

for i, step in enumerate(steps, start=1):
    mas.log(f"running {step}")
    with mas.ui.batch():
        mas.ui.set_text("status", f"Step {i} of {len(steps)}: {step}")
        mas.ui.set_progress("main_bar", i * 100 // len(steps))
        mas.ui.append_text("log", f"{step} done")

For interactive widgets, register handlers and start the listener once. The listener is a daemon thread, so the script still exits when your main function returns.

python
import mas

paused = False

def toggle_pause():
    global paused
    paused = not paused
    mas.ui.set_text("status", "Paused" if paused else "Running")

mas.ui.on_click("pause_btn", toggle_pause)
mas.ui.start_listener()

mas.ui.wait_for_event(timeout=30.0) is the blocking alternative when you want the script to stop and wait for a click. A table can hold buttons too: build a cell with mas.ui.cell_button(id=..., label=...) and handle its id like any other button. The full method list, with signatures and defaults, is on Runtime UI.

Checklists before you ship

Argument form:

  • Every argument widget has a non-empty, identifier-safe, unique key.
  • Required fields are marked required.
  • Combo Box and Radio Group widgets have their options filled in.
  • Number Input and Slider have sensible min and max values.
  • You ran Preview and the form is legible.
  • You clicked Save after the last change, so ui.xml and script_args.py are current.

Runtime dashboard:

  • Every widget has a meaningful, identifier-safe, unique name.
  • Every mas.ui.* call uses a name that exists in the .uibrt file.
  • Table row keys match the table’s columns.
  • Multi-widget refreshes are wrapped in mas.ui.batch().
  • start_listener() is called once, after all handlers are registered.
  • The macro still completes if the user never touches an interactive widget.

Layout tips

  • Work within 932 pixels. The default window is 980 pixels wide with 24 pixels of padding on each side.
  • Stack top to bottom. Forms read as a vertical list. Use the auto-layout button to tidy a tab, and the snap grid to keep edges aligned.
  • Group with intent. A Group Box or a captioned Separator does more for readability than pixel nudging.
  • Preview often. Preview renders the real window and is the fastest way to catch a cramped layout.
  • Keep tabs shallow. Two or three tabs is plenty; more usually means the macro is trying to do too much.

Next steps

Related pages

Was this page helpful?

Questions? Ask in Discord