Poser Python Addons

By default Python scripts are run from the Scripts menu whenever the user requests it. However, more advanced tools written in Python might want a tighter integration with Poser. A Python poseraddons module exists for this, and developers can make their own modules loaded at startup. This will allow additional functionality including, but not limited too, methods called at Poser startup/shutdown, methods called at scene creation/deletion, wx panels incorporated into Poser, ability to load/save user preferences, ability to load/save extra information in Poser scene files, and more.

Addon Packaging

To flag a Python ZIP installation as being an addon, add an element in it's install_python.json for addon: 1. After that you must follow Python conventions for creating a package/module, like including __init__.py

Example install_python.json:

{
    "addon": 1,
    "name": "Poser Hello",
    "version": "1.0.7"
}

Note: The optional scripts section really only needs to list scripts you want to have a Python menu entry for. All scripts included in the ZIP are installed no matter what. Addons will always get a menu under Window > Addons. A single Python ZIP may install itself as an addon, add script menu entries, or do both.

Poser Startup

When Poser is launched, it runs poserStartup.py, this will load any standard Python Addons included with Poser (like the Python Shell window) and any extra Addons installed via ZIPs. Any Addons found have their folder added to the Python sys.path and they are then loaded with __import__() as a Python package. Addons are expected to create a class inheriting from poseraddon, create an instance, and call poser.RegisterAddon(). Then the methods on this object will be called as needed as Poser continues to load. It should go without saying, as this code is always executed at startup, it shouldn't do anything too time/cpu intensive or the user will have a poor experience.

Example Python Addon package __init__.py:

import poser
import wx
import wx.py
import wx.aui
import poseraddon

class PoserHello(poseraddon.Addon):
    def __init__(self):
        self.addonInfo['id'] = 'com.bondware.poserHello'
        self.addonInfo['author'] = 'Bondware, Inc'
        self.addonInfo['copyright'] = '(c) 2020-2021 Bondware, Inc'
        self.addonInfo['name'] = 'Poser Hello'
        self.addonInfo['version'] = '1.0.7'
        self.addonInfo['observer'] = 0
        self.addonInfo['scenedata'] = 0
        self.win = None

    def load(self):
        man = poser.WxAuiManager()
        root = man.GetManagedWindow()
        self.win = wx.py.shell.Shell(root, introText="Hello !")
        man.AddPane(self.win, wx.aui.AuiPaneInfo().DefaultPane().Name("com.bondware.poserHello").Caption("Poser Hello").Show().FloatingSize(wx.Size(450, 300)))

    def unload(self):
        pass

poser.RegisterAddon("com.bondware.poserHello", PoserHello())

 

Poseraddons Module

Refer to the classes in Runtime/Python/addons/poseraddon.py for the full API of methods you can override in your own subclasses to implement advanced behaviors. Note, you must use multiple inheritance if you want to take advantage of the extra classes and set the appropriate flags in the addonInfo dictionary.

# This is the primary base class for Poser addons
# Your addon should inherit from this class.

# API Revision history:
#
# 1.2 Added cameraChanged and lightsChanged callback.
#      To use these callbacks, your addon must set its version field to 1.2.
#      Released with Poser 10.0.2
#
# 1.1 Added objectsInternalRenamed callback.
#      To use that callback, your addon must set its version field to 1.1.
#      Released with Poser 10.0.0
#
# 1.0 Initial release with Poser 9.0.3

class Addon:
    # The constructor. Fill in the addonInfo structure, but do not do
    # much beyond that. This may be called at a point in time where
    # Poser is not fully initialized yet and calls to the Poser Python API
    # may fail or crash Poser.
    def __init__(self):
        pass

    # Poser is fully initialized and your plugin is being loaded.
    # Fill in your data structures, build a GUI, do what your plugin does.
    def load(self):
        pass

    # Your plugin is unloaded from Poser, clean up your data, close open files,
    # close your custom GUI. Please leave no trace.
    def unload(self):
        pass

    # addons must fill this dictionary
    addonInfo = { 'id' : 'com.bondware.addon', # set this to a unique ID
    'author' : 'Bondware, Inc', # author info
    'copyright' : '(c) 2019 Bondware, Inc',
    'name' : 'AddOn', # this is the name of your plugin that will be visible in the GUI
    'version' : '1.1',
    'observer' : 0, # set to 1 if your addon implements the methods from SceneObserver
    'scenedata' : 0, # set to 1 if your addon implements the methods from SceneDataSaver
    'prefsdata' : 0, # set to 1 if your addon implements the methods from PrefsSaver
#   'apiversion' : '1.0' # set this to the version of the addon API your addon is built for
        # this defaults to 1.0 so that older scripts that did not set this field will run in 1.0 mode
        # make sure to set this to the current version in your addon!
     }

# These methods will not get called immediately when things happen
# They get called when the program flow is finished with its work and
# returns to regular event processing
class SceneObserver:
    def objectsAdded(self, objects):
        pass
    def objectsDeleted(self, objects):
        pass
    def objectsRenamed(self, objectsOldNames):
        pass
    def objectsInternalRenamed(self, objectsOldInternalNames): # API V1.1 or higher
        pass
    def objectSelected(self, selection):
        pass
    def sceneDeleting(self, scene):
        pass
    def sceneCreated(self, scene):
        pass
    def frameChanged(self):
        pass
    def materialsChanged(self, materials):
        pass
    def cameraChanged(self): # API V1.2 or higher
        pass
    def lightsChanged(self): # API V1.2 or higher
        pass

class SceneDataSaver:
    # This method will be called when a Poser scene is saved.
    # Your addon should return a dictionary that can be serialized.
    # Do not make any assumptions about how and where your dictionary is stored.
    # It may be in the PZ3, it may be outside of the PZ3,
    # it may be as ASCII text or as binary. Under no circumstances
    # try to read, write or modify the addon data stored in a PZ3 directly.
    def saveData(self):
        return None

    # This method will be called when a Poser scene is loaded
    # that contains data saved by your addon. You will receive
    # the dictionary that your addon passed into saveData() when
    # the scene was saved.
    def loadData(self, data):
        pass

class PrefsSaver:
    # This method is called when Poser asks your addon to save its preferences.
    # Typically this happens when Poser exits or when an addon explicitly asked
    # for the preferences to be saved.
    # Return a dictionary that can be serialized.
    def savePrefs(self):
        return None

    # This method will be called after Poser has launched and the addons are loaded.
    # You will receive the dictionary that your addon passed to savePrefs() when
    # your addon was asked to save the prefs.
    def loadPrefs(self, data):
        pass

Sample Addon Script

For an example of an addon script, download PoserHello.zip

© 2020-2021 Bondware, Inc. Last updated November 23, 2021