OSGEdit extension system


The new extension system allows customizing the editor to fit one's needs. You may find three types of elements in an extension:
  1. Plugins: These elements add new functionality to the editor
  2. Layouts: Change the default presentation of OSG objects, defining alternative ways to arrange items visually, the desired widget to represent each property, and even which properties are to be shown.
  3. Data: Resources for the plugins (images, osg files, etc)

Plugins

The plugin system is based on the idea of registering new classes into the core. It is C++ oriented, in the sense that OSGEdit does not expect any entry function to be declared. Plugins must use the C++ static initialization capabilities to register their new classes.

For example, even OSGEdit core registers its classes with core plugins located in the core extension.

Plugin classes must be registered in factories, that will instance them by name. You do not need to provide a sample instance, as OSGEdit implements a templatized version of the prototype design pattern that allows registering types insted of instances. We will get to this later.

There are a list of abstract classes that you can extend to provide new functionality, and for each of these classes, there is a factory where you can register your own plugged-in subclasses:

Class Factory Register Description
LayoutControl ControlFactory REGISTER_CONTROL A widget, used to edit OSG object properties
Control3D Control3DFactory REGISTER_CONTROL_3D The OSGEdit manipulators (can be registered but will be ignored right now)
Action ActionFactory REGISTER_ACTION[_FULL] User actions, that can be presented as buttons on the user interface (by editing osgedit.ui)

There are plans to extend this list and provide extensibility for:
Additionally, you can create your own wrappers for the reflection mechanism. This would allow editing your own osg::Objects with OSGEdit.

Registering

The mechanism for registering your own classes from a plugin is very simple, and uniform:
  1. Define your class
  2. Register it with static C++ initialization. There are macros to make this transparent, and they are always called REGISTER_X.
    For example: REGISTER_CONTROL(MyDerivedControlClass);
An special case is for the actions, that may be registered with UI attributes. You have the following macros:
REGISTER_ACTION(ActionClass, Label);
REGISTER_ACTION_FULL(ActionClass, gtk-stock-id, Label, Tooltip);

The parameters have the following meaning:


LayoutControl

A layout control must do its work by reimplementing the following methods:
IMPORTANT: Remember to avoid infinite event recursion. You will have some event handler triggered when the user modifies the control. You must check that the new value is different from the previous one before updating the properties. This will have two benefits:
  1. Avoid infinite event recursion. GTK also triggers an event when you update the value of a widget programatically, so if the user updates a widget, you change the property, and the property forces a "refresh", you will update the widget value, triggering another event, and then you will have the infinite recursion.
  2. Any time that you update a property, a command is generated automatically, allowing the user to "undo" this action. If you avoid updating properties when the values are actually unchanged, you will not generate confusing void undo stages.


Control3D

Control3D is a manipulator like those from osgManipulator. In the future, OSGEdit should use osgManipulator if possible, but this OSGEdit framework was already defined before osgManipulator was published.
The name is inverted because of C restriction of starting with a number.
Take care with this one, you can define new 3D controls, and even register them, but you won't be able to use them unless you modify the OSGEdit core. I won't document them further before the support is more flexible or we migrate to osgManipulator.

Action

This is the most powerfull plugin, as it allows providing new elements in the menus and toolbar. There is not any support for automatic registration into menus os toolbars yet. This is planned for the future. In the meantime, you can simply modify the osgedit.ui file to add your new actions where you want them.

The action interface that you have to implement is very simple:
To access all the OSGEdit features (the scenegraph for example), you can use the OSGEdit class in the sdk library. There you have methods to do, hopefully, anything that you need. For example, you can access the user selection, or the reflected scene root, load a new scene, save the current scene, reflect an OSG object, show the different windows, etc.

You will find lots of examples of this in the core actions provided by OSGEdit.

Wrappers

TO-WRITE


Events

OSGEdit provides some basic support for catching events and executing your code. You will find some of these events in the OSGEdit class of the sdk library, with the "signal_" prefix. They work exactly the same way as Gtk signals (it uses sigc library). For example, this allows executing your code when the user tries to load a scene, and block this loading, or when a command is executed, or undone, or when some object is added to another, or deleted from it. You do not have to register any class to access this feature, but you will have to register your event handlers from your plugin's static initialization explicitly.


Layouts

Another way of extending OSGEdit is by providing new layouts for the OSG objects. The layout affects not only how the properties of this object will be arranged visually, but also which of the available widgets will be used to display these properties. For example, there are several widgets for editing strings (single-line text control, text area control, file control, source code control, ...), and the layout provided for the osg::Shader says that the _shaderSource attribute must be edited with a source code control with C syntax highlighting.

You define a layout for a type of Object by creating a XML file. This file has the following unformal syntax:


<?xml version="1.0" encoding="iso-8859-1"?>
<layout ignore_missing="true|false">
<tab label="..."/>
<group label="...">
  <item property="...." label="...." control="....">
    <parameter X="Y"/>
  </item>
</group>
</layout>
It is legal to have a layout that does not define any tab or group. If you do not need them, simply add items directly inside the layout node.