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:
- Plugins: These
elements add new functionality to the editor
- 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.
- Data: Resources for the plugins (images, osg files, etc)
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:
||A widget, used to edit OSG object properties
||The OSGEdit manipulators (can be registered but will be
ignored right now)
||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.
- Tool: Similar to Action, but persistent (it keeps active
until another tool is selected)
- GridControl: Widgets meant to be integrated inside grid
The mechanism for registering your own classes from a plugin is very
simple, and uniform:
An special case is for the actions, that may be registered with UI
attributes. You have the following macros:
- Define your class
- 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);
REGISTER_ACTION_FULL(ActionClass, gtk-stock-id, Label, Tooltip);
The parameters have the following meaning:
The new class that you want to register.
Gtk manages icons and default labels with a stock. It has
constants for common Gtk stocks, like for example Gtk::Stock::DELETE
(see Gtk documentation).
This is the label that you would like to be displayed, or an empty
string if the stock label is ok for you.
The information message that will appear if the user leaves the mouse
over the action button.
A layout control must do its work by reimplementing the following
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:
- void setLabel(const
Property names can be very cryptic, this is why one could need a label
instead of the property name. If the osg Object has a layout with
user-defined labels, this method makes even more sense.
- unsigned render(Gtk::Table
*table, unsigned row)
Places this control's GUI in the Gtk table. It is given the first row
where it can place the GUI, and must return the next row that can be
used to render more stuff. This allows using several rows for a single
- virtual void refresh()
When the system calls this method, the control have to re-read the
contents of the property.
- void parseParameter(const
std::string &property,const std::string &value)
This one is optional. Only used if your component has parameter that
can be established from layout files.
- 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.
- 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 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.
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.
- bool run()
This method will be called when the user selects the menu item for this
action, or presses the toolbar button.
You will find lots of examples of this in the core actions provided by
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.
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
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"?>
<item property="...." label="...." control="....">
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.
It is the main node, containing all the layout
If true, OSGEdit will not show the missing properties (the ones that
exist in OSG but are not in the layout). If false, OSGEdit will add the
missing properties at the end, with their default representation.
Marks the beginning of a new tab. It doesn't enclose its children and
it is on purpose because you can't nest tabs.
The label of the tab.
Marks a group. The contents must be children of the group. Visually it
will be presented as a frame with all the children widgets inside it.
The label placed on the corner of the group.
A control for representing some property.
The name of the property in OSG (with the leading underscore included).
The label for presenting this property in the layout.
The control class that will be used for allowing the user to edit this