Overview
The MeshInspector interface is available to Python as a tree of named entries: tabs, tools, tool windows and their buttons and fields. A script can list the entries, open a tab, start a tool and press buttons, so any sequence of clicks can be repeated by a script.
Run the scripts of this article in the Python window (Home › Python). If you have not used it yet, start with How to Control MeshInspector’s UI with Python.
Understanding the UI Tree
Every entry is reached by a path, a list of names from the top of the tree. Three functions of mrviewerpy do the work:
uiListEntries()lists the entries directly under a path;uiListAllEntries()lists the whole subtree under a path in one call;uiPressButton()presses the button at a path.
Hierarchy Structure
| Level | What it is | Where to find it |
|---|---|---|
| Tab | A Ribbon tab, for example Home, View or Mesh Repair. | Buttons inside the RibbonTabs group. |
| Tool | A tool of the open tab, for example Mesh Healer or Fill Holes. | Buttons inside the Ribbon group (only the tools of the tab that is open now). |
| Parameter | A button, check box, number or text field of an open tool window. | Inside the entry named after the window, for example Mesh Healer. |
The paths of the three levels look like this:
['RibbonTabs', 'Mesh Repair'] # a tab
['Ribbon', 'Mesh Healer'] # a tool of the open tab
['Mesh Healer', 'Repair Resolution'] # a field of the open Mesh Healer window
What an entry tells you
Each entry returned by uiListEntries() has three fields:
name: the name to use in a path;type:button,group(an entry with entries inside),valueInt,valueUint,valueRealorvalueString(fields; check boxes arevalueUintwith the values 0 and 1);status:available, or the reason why the entry cannot be used now.
To see the top of the tree, pass an empty path:
from meshlib import mrviewerpy as mv
for entry in mv.uiListEntries([]):
print(entry.name, entry.type, entry.status)
The list contains the groups RibbonTabs, Ribbon, QuickAccess, Toolbar and RibbonSearch. Open tool windows (such as Mesh Healer) and the panels of the selected object appear next to them.
Listing Available Tabs
from meshlib import mrviewerpy as mv
tabs = mv.uiListEntries(['RibbonTabs'])
print("Available tabs:", [t.name for t in tabs])
Example output in MeshInspector 2.5.9:
Available tabs: ['CT', 'Distance Maps', 'Home', 'Inspect', 'Lines', 'Mesh Edit', 'Mesh Repair', 'Nesting', 'Points', 'Select', 'Toolpath', 'Transform', 'View']
Opening a Tab
To open a tab, press its button in RibbonTabs:
from meshlib import mrviewerpy as mv
mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
mv.Viewer().skipFrames(1)
print("Opened the 'Mesh Repair' tab.")
uiPressButton() waits a few frames by itself; the extra skipFrames(1) makes sure the interface has been redrawn before the next command reads it.
Listing Tools in the Active Tab
After the tab is open, its tools are inside Ribbon:
from meshlib import mrviewerpy as mv
mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
mv.Viewer().skipFrames(1)
tools = mv.uiListEntries(['Ribbon'])
print("Tools in Mesh Repair:", [t.name for t in tools])
Example output in MeshInspector 2.5.9:
Tools in Mesh Repair: ['##DropDownFill Holes', '##DropDownReduce Noise', '##DropDownSeparate Components', '##DropDownStraighten Boundary', 'Decimate Mesh', 'Fill Holes', 'Fix Tunnels', 'Flip Normals', 'Make Delone', 'Mesh Healer', 'Position Vertices Smoothly', 'Re-mesh', 'Rebuild Mesh', 'Reduce Noise', 'Reorient Mesh', 'Rewrap', 'Separate Components', 'Stitch two Holes', 'Straighten Boundary', 'Subdivide Mesh', 'Unite Close Vertices', 'Unite Many Meshes']
Finding Where a Tool Lives
Ribbon shows only the tools of the open tab, so to find the tab of a tool, open the tabs one by one:
from meshlib import mrviewerpy as mv
TARGET_TOOL = 'Mesh Healer'
found = None
for tab in [t.name for t in mv.uiListEntries(['RibbonTabs'])]:
mv.uiPressButton(['RibbonTabs', tab])
mv.Viewer().skipFrames(1)
if TARGET_TOOL in [e.name for e in mv.uiListEntries(['Ribbon'])]:
found = tab
break
if found:
print(f"Tool '{TARGET_TOOL}' is in tab: {found}")
print("Path:", ['RibbonTabs', found], "->", ['Ribbon', TARGET_TOOL])
else:
print(f"Tool '{TARGET_TOOL}' not found.")
Example output:
Tool 'Mesh Healer' is in tab: Mesh Repair
Path: ['RibbonTabs', 'Mesh Repair'] -> ['Ribbon', 'Mesh Healer']
The script leaves the found tab open. A tool can be on several tabs; the script stops at the first one.
Opening a Tool Programmatically
Open the tab first, then press the tool. Most tools need a selected object, so select a mesh in the scene before you run the script.
from meshlib import mrviewerpy as mv
# Step 1: open the tab
mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
mv.Viewer().skipFrames(1)
# Step 2: start the tool
mv.uiPressButton(['Ribbon', 'Mesh Healer'])
mv.Viewer().skipFrames(1)
print("Tool 'Mesh Healer' launched.")
The Mesh Healer window opens on the right, just as if you clicked the button. Pressing the same tool button again closes the window.
Understanding Path Naming
The names in the tree are not always the captions you see on the Ribbon:
- Tools are listed by their internal names. The button with the caption Simplify is
Decimate MeshinRibbon, Remesh isRe-mesh, Auto Repair Mesh isRebuild Mesh, and Section on the Inspect tab isObject Section. - Windows use the title shown on the window. Pressing
['Ribbon', 'Decimate Mesh']opens a window namedSimplify, and['Ribbon', 'Object Section']opens a window namedSection. Use these names for the parameters, for example['Section', '<parameter>']. - Entries that start with
##are hidden helper names, such as##DropDownFill Holesfor the arrow that opens the drop-down list next to Fill Holes. - Names are exact. Case, spaces and hyphens must match.
So always list the entries with uiListEntries() before you press a button or read a value.
Checking Whether a Button Is Available
A button that is unavailable (for example, a tool that needs a selected mesh while nothing is selected) has a status that explains why. Pressing such a button does nothing: the script continues, and only a warning is written to the MeshInspector log. Check the status first:
from meshlib import mrviewerpy as mv
for entry in mv.uiListEntries(['Ribbon']):
if entry.type == mv.UiEntryType.button and entry.status != 'available':
print(entry.name, '->', entry.status)
Example output on the Mesh Repair tab with nothing selected:
Decimate Mesh -> disabled: Select exactly one Mesh
Fill Holes -> disabled: Select exactly one Mesh
Flip Normals -> disabled: Select at least one Mesh
Mesh Healer -> disabled: Select exactly one Mesh
Listing a Whole Window at Once
uiListAllEntries() returns every entry of a subtree with its full path, which is handy to explore a tool window:
from meshlib import mrviewerpy as mv
for path, entry in mv.uiListAllEntries(['Mesh Healer']):
print(path, entry.type, entry.status)
The first lines of the output with the Mesh Healer window open:
['Mesh Healer', '##Auto Repair'] UiEntryType.button available
['Mesh Healer', '##Local Repair'] UiEntryType.button available
['Mesh Healer', 'Disconnected Parts'] UiEntryType.valueUint available
['Mesh Healer', 'Flipped Normals'] UiEntryType.valueUint available
['Mesh Healer', 'Holes'] UiEntryType.valueUint available
['Mesh Healer', 'Repair Resolution'] UiEntryType.valueReal available
['Mesh Healer', 'Repair Selected'] UiEntryType.button available