= XRCed Component Plugins =
<<TableOfContents()>>

This is a short guide on using new XRCed plugin framework to include support for XRC files with new or custom interface elements.

== Note about XML resource handlers ==
Each XRC-loadable interface element must have a corresponding resource handler class registered with the  corresponding '''XMLResource''' object (using '''AddHandler''' method). Handlers for the standard wxPython classes are registered automatically when you import '''xrc''' module. A component plugin for a non-standard class must register the resource handler explicitly, in order to be able to create a test view. Normally a custom resource handler class should be in a separate module accessible from PYTHONPATH. You can also put this module in the same directory as the component plugin module without using PYTHONPATH.

== What are component plug-ins ==
A component plugin is defined using one of classes derived from '''Component''' base class ('''component''' module). First a component object must be constructed, then it is populated with data defining its behavior, and finally it must be registered with the plug-in framework using '''Manager.register()'''. Sometimes there are additional steps involved, such as modifying '''parentChildGroups''' dictionary to include new component groups, deriving special component classes, etc.

== Python vs. manifest files ==
There are two ways to create component object:

 * Using pure Python code, in a plug-in module imported by XRCed on start-up.
 * Using a CRX manifest file. The object is created from XML data, CRX files can be edited in XRCed using ''meta-component'' mode.
For simple interface elements the second method is probably easier to use, as it does not require knowing all the parameters for component class constructor and methods.

== Example of a custom plug-in ==
Here's an example of defining a plug-in for '''gizmos.LEDNumberCtrl''' class. This is a LED-like interface element from contrib '''gizmos''' library included in wxWidgets and wrapped as '''gizmos''' wxPython module. First, we need a resource handler. Looking at the source code in src/gizmos/ledctrl.cpp, we can easily find out which window styles and constructor parameters are needed to create an object. The handler class should normally define two standard methods: '''CanHandle()''' and '''DoCreateResource()'''. We will include support for '''pos''', '''size''' and '''value''' XRC attributes.

'''File: xh_ledctrl.py'''

{{{
import wx
import wx.xrc as xrc
import wx.gizmos as gizmos
class LEDNumberCtrlXmlHandler(xrc.XmlResourceHandler):
    def __init__(self):
        xrc.XmlResourceHandler.__init__(self)
        # Standard styles
        self.AddWindowStyles()
        # Custom styles
        self.AddStyle('wxLED_ALIGN_LEFT', gizmos.LED_ALIGN_LEFT)
        self.AddStyle('wxLED_ALIGN_RIGHT', gizmos.LED_ALIGN_RIGHT)
        self.AddStyle('wxLED_ALIGN_CENTER', gizmos.LED_ALIGN_CENTER)
        self.AddStyle('wxLED_DRAW_FADED', gizmos.LED_DRAW_FADED)
    def CanHandle(self,node):
        return self.IsOfClass(node, 'LEDNumberCtrl')
    # Process XML parameters and create the object
    def DoCreateResource(self):
        assert self.GetInstance() is None
        w = gizmos.LEDNumberCtrl(self.GetParentAsWindow(),
                                 self.GetID(),
                                 self.GetPosition(),
                                 self.GetSize(),
                                 self.GetStyle())
        w.SetValue(self.GetText('value'))
        self.SetupWindow(w)
        return w
}}}
Next step is defining a component plug-in class for using in XRCed. In this case we can use base '''Component''' class, which has all necessary functionality for control-like components and predefines standard window attributes and styles.

=== Python way ===
'''File: ledctrl.py'''

{{{
from xh_ledctrl import *
from component import *
# Construct a new component object, belonging to 'control' group
c = Component('LEDNumberCtrl', ['control'], ['pos', 'size', 'value'])
# Set custom window styles
c.addStyles('wxLED_ALIGN_LEFT', 'wxLED_ALIGN_RIGHT',
            'wxLED_ALIGN_CENTER', 'wxLED_ALIGN_FADED')
# Register
Manager.register(c)
# Put under 'gizmo' pop-up menu with order index 10
Manager.setMenu(c, 'gizmo', 'LED number', 'LED-like control', 10)
}}}
That's all! After putting the plug-in and the resource file in one of plug-in directories defined in XRCEDPATH you can create and test interfaces containing this control. Note that it can only be put inside a window object, because we specified ''''control'''' group in the group list ctor parameter, which restricts the place in the XML tree where it can be put.

=== Visual way ===
And now for something completely different! Start XRCed with '''--meta''' option, then open right-click tree pop-up menu, select "Append > component" and fill attribute panel as shown:

{{attachment:LEDCtrl_crx.png}}

Then save the result under '''ledctrl.crx''' in a plug-in directory. After restarting XRCed (in normal mode) you should obtain the same result as with Python-coded plug-in.

== Documentation and additional resources ==
 * http://xrced.sourceforge.net/api_doc/ - epydoc-generated HTML docs for XRCed classes related to component plugins
 * [[XRCed Refactoring Project#framework|XRCed Refactoring Project; Plugin framework]] - some more details about plug-in component classes
 * Use the f^Hsource! Especially '''plugins/core.py''' and '''plugins/controls.py''' can be helpful, and probably '''component.py''' too.