UI Builder
Drag-and-drop designer for argument forms (.uibproj) and runtime dashboards (.uibrt). Build a real application around your Python macro without writing any frontend code.
mas.ui.* calls.
The Two Project Types
Argument Forms
.uibprojThe window the user fills in before a macro runs.
11 input widgets · validation · generates script_args.py
Runtime Dashboards
.uibrtThe live panel shown during a macro run.
7 runtime widgets · driven by mas.ui.* · live progress, logs, charts, tables
A macro can have one, the other, both, or neither. They are independent files. Only the Python script (src/app.py) is required.
The Editor at a Glance
┌──────────────────────────────────────────────────────────────────────┐ │ Toolbar Save · Export · Preview · Snap · Generate Args │ ├───────────┬──────────────────────────────────────────┬───────────────┤ │ Palette │ Tabs: [ General ] [ Advanced ] [+] │ Inspector │ │ │ ┌──────────────────────────────────────┐ │ │ │ Argument │ │ │ │ Properties: │ │ Inputs │ │ Canvas │ │ geometry, │ │ Layout │ │ (the window you are designing) │ │ key, label, │ │ Runtime │ │ drag, move, resize widgets here │ │ required, │ │ │ └──────────────────────────────────────┘ │ default... │ └───────────┴──────────────────────────────────────────┴───────────────┘
- Palette (left) — every widget, grouped into Argument Inputs, Layout, and Runtime Display. Drag onto the canvas.
- Canvas (center) — a scale model of the window. Widgets are positioned with absolute pixel coordinates.
- Tabs (above the canvas) — a window can have several tabs (forms only).
- Inspector (right) — every property of the selected widget plus its argument metadata.
- Toolbar (top) — save, export, Preview (renders the real form), snap-to-grid, alignment, and Generate Args.
Argument Forms (.uibproj)
An argument form is a window of input fields. Each input field carries a key, and at run time MAS turns every field into a command-line argument the script reads.
The 11 Argument Widgets
Each produces one argument. Default sizes are in pixels; the canvas is 980 × 640 with 24 px padding, so the usable width is 932 px.
| Widget | Produces |
|---|---|
| Text Input | string |
| Text Area | string |
| Number Input | int / float |
| Slider | int / float |
| Checkbox | bool |
| Combo Box | chosen string |
| Radio Group | chosen string |
| File Picker | file path |
| Directory Picker | folder path |
| Date Picker | date string |
| Time Picker | time string |
Layout Widgets
These three add visual structure and produce no argument.
Label
Static helper text
Separator
A horizontal/vertical divider with an optional caption
Group Box
A titled container that groups related fields
Argument Metadata
Every argument widget has, in addition to its own options, a block of argument metadata in the Inspector.
| key (required) | The argument name. Must be a valid Python identifier (start with a letter or underscore, then letters/digits/underscores). Must be unique within the project. An argument widget with an empty key is silently skipped on export. |
| required | If on, the form will not let the user proceed without a value (and the generated argument is marked required=True). |
| helpText | A short explanation, surfaced as a tooltip / help string. |
| showLabel, labelPosition, labelGap | Control whether and where the field's label is drawn (top or left). |
From Form to Script — the key Contract
The key is the contract between the form and the script. Choose them deliberately and keep them stable.
Click Generate Args → writes src/script_args.py
input_path = args.general.input_file # File Picker, key "input_file"
threads = args.general.thread_count # Number Input, key "thread_count"
dry_run = args.advanced.dry_run # Checkbox, key "dry_run"
Widget types map to Python types automatically:
| Widget | Generated as | Python type |
|---|---|---|
| Checkbox | action='store_true' | bool |
| Number Input / Slider | type=int (or float) | int / float |
| Combo Box / Radio Group | type=str, choices=[...] | str |
| everything else | type=str | str |
Tabs
Group related fields onto separate tabs when a form gets long — a General tab for everyday options and an Advanced tab for the rest. Each tab becomes a Python namespace in the generated code (args.general.input_file). A tab's name is lowercased and slugged: "My Settings" becomes my_settings.
The Action Bar
Below the tabs sits the action bar — the row of buttons that closes the window. New projects start with Cancel + Run. Edit text, role (run / cancel / reset / custom), style (primary / secondary / danger), and alignment in the Inspector. For most macros the default is exactly right.
Validation
The UI Builder checks a project before letting you export. The rules that matter for argument forms:
- The window must contain at least one tab.
- Every widget id is unique across the project.
- Every argument widget's
keyis non-empty and a valid identifier. - Argument
keysare unique within the project. - Combo Box and Radio Group have at least one option.
- Width and height are positive numbers.
What the UI Builder Produces
.uibproj ──Generate Args──▶ src/script_args.py (your script imports this) │ └────────Export XML──────▶ ui.xml (Studio renders this)
- script_args.py — generated argparse code, grouped by tab, parses
sys.argvon import. Never hand-edit it. Regenerate when the form changes. - ui.xml — the structural description Studio reads to render the input window. Export it whenever the form changes.
Runtime Dashboards (.uibrt)
A runtime dashboard is the live panel Studio shows next to a device while a macro runs. You design it visually here (a .uibrt file). You drive it from your script with mas.ui.* calls.
name (set in the UI Builder Inspector). That name is the only handle your script has on the widget. A typo between the .uibrt name and the mas.ui.* call is the most common dashboard bug — the call simply updates nothing.
Make each name a valid Python identifier (snake_case: status_label, items_chart), unique within the dashboard, and named for meaning, not type.
Display Widgets — the script writes, the user reads
| Widget | Shows | Driven by |
|---|---|---|
| Runtime Label | a line of text | set_text |
| Progress Bar | progress min → max | set_progress |
| Chart | line / bar / pie chart | add_data_point, set_chart_data |
| Text Area | scrolling text / log | append_text, set_textarea |
| Table | rows under fixed columns | set_table_data, append_table_row |
Interactive Widgets — the user acts, the script reads
| Widget | Is | Read with |
|---|---|---|
| Button | a clickable button | wait_for_event · on_click |
| Text Input | a field the user types into | get_input_value · on_change |
From Dashboard to Script — the name Contract
Every widget's name is the first argument to its corresponding mas.ui.* call:
mas.ui.set_text("status_label", "Logging in…")
# A Progress Bar named "download_bar"
mas.ui.set_progress("download_bar", 60)
# A Button named "stop_btn" — Model B (callback)
mas.ui.on_click("stop_btn", handle_stop)
mas.ui.start_listener()
Full mas.ui.* reference: API Reference → Runtime UI.
Batch Updates for Smooth Refreshes
Each mas.ui.* call is one round-trip to Studio. Wrap a multi-widget refresh in mas.ui.batch() so they send as a single call. It is the difference between a smooth dashboard and one that flickers behind a tight loop.
mas.ui.set_text("status", f"Step {i}/{n}")
mas.ui.set_progress("main_bar", i * 100 // n)
mas.ui.add_data_point("rate", value=rate, label=str(i))
Checklists Before You Ship
Argument form (.uibproj)
- Every argument widget has a non-empty, identifier-safe, unique
key. - Required fields are marked
required. - Combo Box / Radio Group widgets have their options filled.
- Number Input / Slider have sensible
min/max. - You ran Preview and the form is legible.
- Generate Args so
script_args.pyis current. - Export XML so
ui.xmlis current.
Runtime dashboard (.uibrt)
- Every widget has a meaningful, identifier-safe, unique
name. - Every
mas.ui.*call uses a name that exists in the.uibrt. - Table row dict keys match the table's columns.
- Multi-widget refreshes are wrapped in
mas.ui.batch(). start_listener()is called once, after registering all handlers.- The macro still completes if the user never touches an interactive widget.
Layout Tips
- Work within 932 px. The canvas is 980 px wide with 24 px padding each side. Wide widgets default to the full width.
- Stack top to bottom. Forms read as a vertical list. Use the toolbar's align/distribute/stack tools to keep edges and gaps tidy.
- Group with intent. A Group Box or captioned Separator does more for readability than careful pixel nudging.
- Preview often. The Preview button renders the real form — 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.