.. _pme-scripting: ========= Scripting ========= PME allows for advanced customization and automation using Blender's `Python API `_. This article provides an overview of PME's scripting capabilities and explains the built-in global variables and functions. .. NOTE: Not necessary for furo or book themes. .. .. contents:: .. :local: .. :depth: 2 .. :class: this-will-duplicate-information-and-it-is-still-useful-here --------- Tutorials --------- - **Video**: `Introduction to Scripting with Python in Blender (vimeo.com) `_ - **Video**: `Task Automation with Python Scripting in Blender (youtube.com) `_ - `Python for Non-Programmers (python.org) `_ - `Blender Python API `_ - `Blender/Python Quickstart `_ ---------------- Global Variables ---------------- Variables available within each PME slot editor. .. list-table:: :header-rows: 1 :widths: 25 75 * - **Variable** - **Description** * - ``menu`` - Name of the active menu * - ``slot`` - Name of the active slot * - ``C`` - `bpy.context `_ * - ``D`` - `bpy.data `_ * - ``O`` - `bpy.ops `_ * - ``T`` - `bpy.types `_ * - ``P`` - `bpy.props `_ * - ``L`` - Current `UILayout `_ object .. code-block:: python L.box().label(text="My Label") * - ``E`` - Current `Event `_ object .. code-block:: python E.ctrl and E.shift and message_box("Ctrl+Shift Pressed") * - ``U`` - `pme.UserData <#pme.UserData>`_ instance for user data storage .. code-block:: python U.foo = "value" U.update(foo="value1", bar="value2") U.foo U.get("foo", "default_value") ---------------- Global Functions ---------------- Functions available within PME slot editors. Different functions are available in Command tab and Custom tab. .. _pme-common-functions: Common Functions **************** .. py:function:: execute_script(path, **kwargs) Execute an external Python script. :param str path: Script file path. Relative path (from ``pie_menu_editor`` folder, recommended) or absolute path. :param kwargs: Additional keyword arguments passed to the script. :return: ``return_value`` from the script, or ``True`` by default. .. warning:: - Only place and execute scripts from trusted sources - Review contents before execution and verify in a backup or test environment if necessary - Scripts may contain operations that affect your environment, such as file operations or settings changes **Variables available in script**: ``kwargs``, ``__file__``, ``return_value``, all PME global variables **Examples**:: # Basic execution and return value execute_script("scripts/hello_world.py", msg="Hello World!") message_box(execute_script("scripts/get_message.py")) # scripts/hello_world.py message_box(kwargs["msg"]) # scripts/get_message.py return_value = "Hi!" # Processing with parameters # scripts/process_data.py kwargs = locals().get("kwargs", {}) result = my_function(kwargs.get("param1"), kwargs.get("param2", "default")) return_value = result # Call result = execute_script("scripts/process_data.py", param1=200, param2="Hello") # UI drawing in Custom tab # scripts/custom_ui.py msg = kwargs.get("msg", pme.context.text or "Default Message") box = L.box() box.label(text=msg, icon=pme.context.icon, icon_value=pme.context.icon_value) # Call execute_script("scripts/custom_ui.py", msg="Custom message") .. py:function:: props(name=None, value=None) 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**:: # 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() Retrieve the context-sensitive paint settings. :return: The current paint settings or ``None`` if not in a paint mode. **Example**:: ps = paint_settings(); ps and L.template_ID_preview(ps, 'brush') .. py:function:: find_by(collection, key, value) Find the first item in ``collection`` where ``key`` equals ``value``. :return: Collection item if found, otherwise ``None``. **Example**:: m = find_by(C.active_object.modifiers, "type", 'SUBSURF') .. py:function:: setattr(object, name, value) Same as Python's built-in :func:`setattr`, but returns ``True`` after setting. :return: ``True`` .. _pme-command-tab-functions: Command Tab Functions ********************* .. py:function:: open_menu(name, slot=None, **kwargs) 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 and is currently available. Returns ``False`` when the target is missing, disabled, poll-blocked, or the requested slot is not found. **Example**:: # 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) 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) Redraw UI areas or regions. :param str area: The :attr:`Area.type ` to redraw. Redraw all areas if ``None``. :param str region: The :attr:`Region.type ` to redraw. Redraw all regions if ``None``. :return: ``True`` .. py:function:: close_popups() Close all popup dialogs. :return: ``True`` .. py:function:: overlay(text, **kwargs) 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**:: overlay('Hello PME!', offset_y=100, duration=1.0) .. py:function:: message_box(text, icon='INFO', title="Pie Menu Editor") 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) 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**:: # 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) 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 menu exists and is currently available. Returns ``False`` without drawing when the target is missing, disabled, or poll-blocked. .. py:function:: operator(layout, idname, text="", icon='NONE', emboss=True, icon_value=0, **kwargs) Similar to :meth:`UILayout.operator() `, but allows filling operator properties. :param layout: A :class:`UILayout ` instance. :param str idname: Identifier of the operator. :return: :class:`OperatorProperties ` object. **Example**:: 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) 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**:: L.label(text="My Custom Icon", icon_value=custom_icon("p1")) .. py:function:: panel(pt, frame=True, header=True, expand=None, area=None, root=False, poll=True, layout=None) Draws a panel by its ID. :param pt: Panel class or panel class name string. If string, the corresponding class is searched from ``bpy.types``. :type pt: Union[str, Type] :param bool frame: Controls whether to frame the panel. If ``True``, uses ``layout.box()``. If ``False``, uses ``layout.column()``. :param bool header: Controls panel header display style. :param expand: Controls initial expansion state of panel. ``True``: start expanded, ``False``: start collapsed, ``None``: retain previous state. :type expand: Optional[bool] :param area: :attr:`Area.type ` the panel should be drawn against (e.g. ``'VIEW_3D'``, ``'PROPERTIES'``). Useful when drawing an editor-specific panel (such as ``VIEW3D_PT_*``) from a popup dialog or a different editor, so the panel's ``poll`` / ``draw`` can resolve the expected ``space_data``. Use ``None`` or ``'CURRENT'`` to keep the current context. :type area: Optional[str] :param bool root: If ``True``, draws the panel directly on the current ``pme.context.layout`` without wrapping it in an extra ``box()`` / ``column()``. When ``True``, the ``frame`` and ``layout`` parameters are ignored. Use this to avoid an extra layer of nesting in tightly controlled layouts. :param bool poll: Controls whether to execute the panel's ``poll`` method. If ``True``, checks the panel's display conditions. :param layout: Specify a custom layout. :type layout: Optional[Any] :return: True :rtype: bool **Example**:: panel("MATERIAL_PT_context_material", True, True, True) # Change panel size L.scale_x = 0.8; panel("USERPREF_PT_interface", layout=L.box()) # Draw a 3D View panel from a popup dialog panel("VIEW3D_PT_tools_meshedit_options", area='VIEW_3D') # Draw without an extra wrapping box/column panel("MATERIAL_PT_context_material", root=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:: - Only place and execute scripts from trusted sources - Review contents before execution and verify in a backup or test environment if necessary - Scripts may contain operations that affect your environment, such as file operations or settings changes ---------------------------- 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: .. code-block:: 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``) .. code-block:: 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 .. code-block:: 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. .. code-block:: python U = pme.context.globals['U'] # Get UserData instance U.update(tool_state="active", count=5) print(U.tool_state) # "active"