29.2. How to Build Your Interface

DialogViz provides a set of basic components that you are already used to using in a graphical user interface.

DialogViz puts the following classes at your disposal: (the indentation shows class derivation).


Figure 29.3. SoTopComponent class


Nodes with a grouping behavior are the SoTopLevelDialog( C++ ), SoMenuBar( C++ ), and SoMenuPopup( C++ ) nodes, and the SoDialogGroup( C++ ) -derived classes SoColumnDialog( C++ ), SoRowDialog( C++ ), and SoTabDialog( C++ ). (The launcher classes are explained next). These different containers can be used together to create a well-organized interface.

To add a child to these classes, simply use the addChild() method similar to an SoGroup( C++ | Java | .NET ) node. All other SoGroup( C++ | Java | .NET ) methods like insertChild(), replaceChild(), ..., are available as well.

[Warning]

Careful, although these classes have similar methods, they do not inherit from the SoGroup( C++ | Java | .NET ) class.

Each one of these nodes manages its own children. Container nodes can be nested to create more complex groupings.

SoRowDialog( C++ ) manages the position of its children to make rows: it puts one child beneath the other. When resizing, the SoRowDialog( C++ ) component resizes all its children according to the constraints on them. The size difference between the initial and final size is evenly distributed.

SoColumnDialog( C++ ) manages the position of its children to make columns: the children are placed side by side.

SoTabDialog( C++ ) organizes its children by pages. This component can be very useful when there are a large number of controls that would not fit well on a single page.

SoTopLevelDialog( C++ ) has the same managing behavior as SoRowDialog( C++ ). The difference is that SoTopLevelDialog( C++ ) can have a child (only one) of type SoMenuBar( C++ ) and some other children of type SoDialogComponent( C++ ). If an SoMenuBar( C++ ) child exists, a menu bar is built at the top of the window. The SoMenuBar( C++ ) can have children of type SoMenuPopup( C++ ) which constitute the sub-menus. The items of the menu will be children of the SoMenuPopup( C++ ) nodes.

Like other extension modules, DialogViz must be explicitly initialized. The method to use is: SoDialogViz( C++ )::init().

There are two ways to build a graphical interface A complete interface, or any part of any interface, may be read from one or more Inventor format files. An interface, or any part of an interface, may be created programmatically just like any other Open Inventor nodes.

A 2D dialog window is built by using the SoTopLevelDialog( C++ )::buildDialog() method. The show() method draws the dialog. A 3D dialog is built by adding the DialogViz nodes to a displayed scene graph. See the section called “2D/3D Differences” for more details.

The way to build a 2D and a 3D DialogViz interface is the same, but some rules must be followed for the two cases:

  • 2D interface:

    In the 2D case, DialogViz builds the user interface on your 2D desktop using the local native 2D user interface toolkit (e.g., Motif, Windows). The user interface will have the appearance of the native UI toolkit. It will be displayed in separate windows that can be moved around on the desktop.

    [Important]

    SoTopLevelDialog::buildDialog(Widget, SbBool) has two arguments. The first argument corresponds to the parent window you want for the DialogViz window, and the second argument specifies if the new window should be mapped inside or outside the parent window.

  • 3D interface:

    • Just add your DialogViz nodes to your Inventor scene graph. In this case, DialogViz components can be treated just like ordinary Inventor nodes (because they are ordinary Inventor nodes).

    • You can use each component independently.

    In the 3D case, the user interface components are drawn using Open Inventor nodes, and are displayed inside the Open Inventor 3D window. You will need to specify an appropriate camera in the scene graph to make sure that that the DialogViz components are positioned in a suitable location relative to the rest of the geometry in the scene. The appearance of the 3D DialogViz components can be customized using skins, described in the section called “DialogViz Skins”.

    [Important]

    An Inventor file can define a DialogViz scene graph which doesn't start with an SoTopLevelDialog( C++ ) component. However, in this case, the file cannot be loaded to build a 2D interface.

  • 2D and 3D interface:

    A loaded DialogViz interface can be used in 2D and 3D at the same time. The 2D dialog box structure must start necessarily with an SoTopLevelDialog( C++ ) to be able to be created. However, it’s possible to render in 3D only a part of the loaded DialogViz structure simply by inserting the requested sub-scene graph in your main scene.

In order to customize your 3D interface, DialogViz allows you to redefine the appearance of the 3D components using skins.

[Important]

Skins only affect the appearance of 3D DialogViz components. The appearance of 2D components depends on your system appearance settings.

All DialogViz classes are derived from the SoDragger( C++ | Java | .NET ) class. So, like draggers, a DialogViz component has some parts you can pick on, and other parts that replace them when they are active or moving. These active parts are often just the same geometry with another color or texture. Each of these pieces has a default scene graph, as well as a special function within the dragger.

Like draggers, you can retrieve a part of any instance by using the getPart() method, and you can set them by using setPart() method.

But draggers also give each part a resource name. When a dragger builds a part, it looks in the global dictionary for the node with that resource name. By adding a new entry in the dictionary, you can override the default. The default part geometries are defined as resources for each class, and can be found in a corresponding file you can change to alter the defaults. The files are listed on each DialogViz component’s reference page. You can make your program use different default resources for the parts by changing the default skins directory located at %OIVHOME%/data/DialogViz/Skins/default/ to your own directory. To define your own directory, you can set the environment variable DIALOGVIZ_SKINS_DIR to be a path to that directory, or use the SoDialogViz::setSkinsDirectory() method in your application.

Currently, several skins are provided:

  • default: all components are single polygons.

  • texture: the components are single polygons and some textures are added to produce 3D effects.

  • transparent: the components are defined with transparency. Useful when you want to insert a DialogViz structure in your scene without obscuring parts of the scene.

The launcher components have been developed to simplify utilization for programmers. The goal of the launcher is to directly load a new SoTopLevelDialog( C++ ) component when it is activated. This is useful primarily when you want to open other dialog windows in the application that are configuration windows or other special-purpose windows that don’t always need to be visible. The presence of the launcher allows the programmer to avoid having to develop an auditor class (See Section 29.3, “Interacting with Your Application” for more details on creating and using auditors) to handle the activation of a control that would be dedicated to open a new window

The scene graph above allows the “TopLevelDialog 1” dialog box to be shown by triggering a push button “PushButtonLauncher”. By changing the check box “CheckBoxLauncher” state, the dialog windows “TopLevelDialog 2” and “TopLevelDialog 3” are launched or hidden at the same time.

SoDialogCustom( C++ ) was created to map any widgets you want to see in a dialog window. For example, it’s very interesting to be able to embed an Open Inventor viewer in the same window with the user interface controls.

The next steps show you how to include a viewer in a DialogViz window:

  • Create a dialog window structure with the SoDialogCustom you will use to map the viewer.

  • Build the dialog box using buildDialog() method.

  • Retrieve the SoDialogCustom node in the dialog scene graph.

  • Create the viewer using the SoDialogCustom::getWidget() method as parent of the viewer.

Here is some sample code:


C++
...
myTopLevelDialog->buildDialog(mainWindow, TRUE);
myTopLevelDialog->show();

// retrieve the DialogCustom in dialog scene graph
customNode = (SoDialogCustom*)
myTopLevelDialog->searchForAuditorId(SbString("theCustom"));

SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(customNode->getWidget());
...
        

This allows you to build an advanced interface that could look like: