(pme-scripting)= # Scripting PME allows for advanced customization and automation using Blender's [Python API](https://docs.blender.org/api/current/). This article provides an overview of PME's scripting capabilities and explains the built-in global variables and functions. ## Tutorials - **Video**: [Introduction to Scripting with Python in Blender (vimeo.com)](https://vimeo.com/28203314) - **Video**: [Task Automation with Python Scripting in Blender (youtube.com)](https://www.youtube.com/watch?v=ZZWSvUgR38Y) - [Python for Non-Programmers (python.org)](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) - [Blender Python API](https://docs.blender.org/api/current/) - [Blender/Python Quickstart](https://docs.blender.org/api/current/info_quickstart.html) ## Global Variables | Variables | Description | |-----------|-------------| | `menu` | Name of the active menu | | `slot` | Name of the active slot | | `C` | [bpy.context](https://docs.blender.org/api/current/bpy.context.html) | | `D` | [bpy.data](https://docs.blender.org/api/current/bpy.data.html) | | `O` | [bpy.ops](https://docs.blender.org/api/current/bpy.ops.html) | | `T` | [bpy.types](https://docs.blender.org/api/current/bpy.types.html) | | `P` | [bpy.props](https://docs.blender.org/api/current/bpy.props.html) | | `L` | Current [UILayout](https://docs.blender.org/api/current/bpy.types.UILayout.html) object

```python
L.box().label(text="My Label")
``` | | `E` | Current [Event](https://docs.blender.org/api/current/bpy.types.Event.html) object

```python
E.ctrl and E.shift and message_box("Ctrl+Shift Pressed")
``` | | `U` | [pme.UserData](#pme.UserData) instance for user data storage

```python
U.foo = "value"
U.update(foo="value1", bar="value2")
U.foo
U.get("foo", "default_value")
``` | ## Global Functions Below is a list of global functions provided by PME. (pme-common-functions)= ### Common Functions ````{py:function} execute_script(path, **kwargs) :noindex: Execute an external Python script. :param str path: Path to the `.py` file. :param kwargs: Additional keyword arguments passed to the script. :return: Value of local variable `return_value` if it exists, otherwise `True`. **Example**: ```python # Display 'Hello World!' message: execute_script("scripts/hello_world.py", msg="Hello World!") # scripts/hello_world.py: # message_box(kwargs["msg"]) # Display 'Hi!' message: message_box(execute_script("scripts/hi.py")) # scripts/hi.py: # return_value = "Hi!" ``` ```` ````{py:function} props(name=None, value=None) :noindex: Get or set the value of a PME Property. :param str name: Name of the property. :param value: New value of the property. :return: PME property container if `name` is `None`, property value if only `name` is given, `True` if setting a value. **Example**: ```python # Get property value using string notation value = props("MyProperty") # Alternative: get property using attribute notation value = props().MyProperty # props() returns property container # Set property value using string notation props("MyProperty", value) # Alternative: set property using attribute notation props().MyProperty = value # props() returns property container ``` ```` ````{py:function} paint_settings() :noindex: Retrieve the context-sensitive paint settings. :return: The current paint settings or `None` if not in a paint mode. **Example**: ```python ps = paint_settings(); ps and L.template_ID_preview(ps, 'brush') ``` ```` ````{py:function} find_by(collection, key, value) :noindex: Find the first item in `collection` where `key` equals `value`. :return: Collection item if found, otherwise `None`. **Example**: ```python m = find_by(C.active_object.modifiers, "type", 'SUBSURF') ``` ```` ````{py:function} setattr(object, name, value) :noindex: Same as Python's built-in `setattr`, but returns `True` after setting. :return: `True` ```` (pme-command-tab-functions)= ### Command Tab Functions ````{py:function} open_menu(name, slot=None, **kwargs) :noindex: Open menu, pie menu, popup dialog or execute a stack key, sticky key, modal operator, or macro operator by name. :param str name: Name of the menu. :param slot: Index or name of the slot for Stack Key execution. :param kwargs: Arguments for Modal / Macro Operators used as local variables. :return: `True` if the menu exists, `False` otherwise. **Example**: ```python # Open the menu depending on the active object's type: open_menu("Lamp Pie Menu" if C.active_object.type == 'LAMP' else "Object Pie Menu") # Call "My Stack Key" slot depending on Ctrl modifier: open_menu("My Stack Key", "Ctrl slot" if E.ctrl else "Shift slot") ``` ```` ````{py:function} toggle_menu(name, value=None) :noindex: Enable or disable a menu. :param str name: Name of the menu. :param bool value: `True` to enable, `False` to disable, `None` to toggle. :return: `True` if the menu exists, `False` otherwise. ```` ````{py:function} tag_redraw(area=None, region=None) :noindex: Redraw UI areas or regions. :param str area: The Area.type to redraw. Redraw all areas if `None`. :param str region: The Region.type to redraw. Redraw all regions if `None`. :return: `True` ```` ````{py:function} close_popups() :noindex: Close all popup dialogs. :return: `True` ```` ````{py:function} overlay(text, **kwargs) :noindex: Draw an overlay message. :param str text: Message to display. :param kwargs: - `alignment`: One of `['TOP', 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM', 'BOTTOM_LEFT', 'BOTTOM_RIGHT']`. Default is `'TOP'`. - `duration`: Duration in seconds. Default is `2.0`. - `offset_x`: Horizontal offset. Default is `10` px. - `offset_y`: Vertical offset. Default is `10` px. :return: `True` **Example**: ```python overlay('Hello PME!', offset_y=100, duration=1.0) ``` ```` ````{py:function} message_box(text, icon='INFO', title="Pie Menu Editor") :noindex: Show a message box. :param str text: Message to display. :param str icon: Icon name (e.g. 'INFO', 'ERROR', 'QUESTION', etc.). :param str title: Window title. :return: `True` ```` ````{py:function} input_box(func=None, prop=None) :noindex: Show an input box. :param func: Function to call with the input value. :param str prop: Path to the property to edit. :return: `True` **Example**: ```python # Rename object: input_box(prop="C.active_object.name") # Display input value: input_box(func=lambda value: overlay(value)) ``` ```` (pme-custom-tab-functions)= ### Custom Tab Functions ````{py:function} draw_menu(name, frame=True, dx=0, dy=0) :noindex: Draw a popup dialog inside another popup dialog or a pie menu. :param str name: Name of the menu (popup dialog). :param bool frame: Whether to draw a frame. :param int dx: Horizontal offset. :param int dy: Vertical offset. :return: `True` if the popup dialog exists, otherwise `False`. ```` ````{py:function} operator(layout, operator, text="", icon='NONE', emboss=True, icon_value=0, **kwargs) :noindex: Similar to UILayout.operator(), but allows filling operator properties. :param layout: A UILayout instance. :param str operator: Identifier of the operator. :return: OperatorProperties object. **Example**: ```python operator(L, "wm.context_set_int", "Material Slot 1", data_path="active_object.active_material_index", value=0) # Same as: # op = L.operator("wm.context_set_int", text="Material Slot 1") # op.data_path = "active_object.active_material_index" # op.value = 0 ``` ```` ````{py:function} custom_icon(filename) :noindex: Get the integer value associated with a custom icon. :param str filename: Icon filename without extension, located in `pie_menu_editor/icons/`. :return: The integer value of the custom icon. **Example**: ```python L.label(text="My Custom Icon", icon_value=custom_icon("p1")) ``` ```` ````{py:function} panel(id, frame=True, header=True, expand=None) :noindex: Draws a panel by its ID. :param str id: ID of the panel. :param bool frame: Draw a framed panel. :param bool header: Draw the panel header. :param expand: `True` to expand, `False` to collapse, `None` to use the current state. :return: `True` **Example**: ```python panel("MATERIAL_PT_context_material", True, True, True) ``` ```` --- ## Auto-run Scripts PME allows you to create Python scripts that automatically execute when Blender starts. To use this feature, place files in the `pie_menu_editor/scripts/autorun` folder using any of these methods: - Direct `.py` files - Folders containing scripts - Symbolic links ```{warning} Scripts in the `autorun` folder are executed directly in PME's context. Only use scripts from trusted sources. ``` ## Add Custom Global Functions To use custom functions in PME: 1. Place your script in `pie_menu_editor/scripts/autorun` folder 2. Register functions using `pme.context.add_global()` Example: ```python def hello_world(): print("Hello World") pme.context.add_global("hello", hello_world) ``` The registered function `hello()` becomes available in: - Command tab - Custom tab - External scripts ## PME Components PME maintains a global context that provides access to commonly used functions, variables, and user-defined additions. This context is accessible through two main interfaces: ````{py:class} pme.context ```{py:attribute} globals :type: dict Access PME's global context dictionary. Contains: - Built-in shortcuts (`C`, `D`, `O`, `L`, etc.) - Registered custom functions and values - User data storage (`U`) ``` ```python from pie_menu_editor import pme # Access globals from external scripts g = pme.context.globals props = g.get('props') user_data = g.get('U') ``` ```{py:method} add_global(key, value) Register a custom function or value in the global context. :param str key: Name for accessing the item :param value: Function or value to register :rtype: None ``` ```python # Register a function def my_tool(): bpy.ops.mesh.select_all(action='TOGGLE') pme.context.add_global("toggle_select", my_tool) # Register a constant pme.context.add_global("MAX_ITEMS", 10) # Access from PME menus via Command tab: # toggle_select() # MAX_ITEMS ``` ```` ````{py:class} pme.UserData Flexible storage for user-defined data that persists during the Blender session. ```{py:method} get(name, default=None) Get a stored value. :param str name: Data key :param default: Value to return if key doesn't exist :return: Stored value or default ``` ```{py:method} update(**kwargs) Update multiple values at once. ``` ```python U = pme.context.globals['U'] # Get UserData instance U.update(tool_state="active", count=5) print(U.tool_state) # "active" ``` ````