This example shows how to add a dialog box and dialog box page to the GUI, and how to manage persistent settings.
It consists of a dialog page (DtExamplePage), which is registered with the application by the plugin's initialization function. The dialog page has a persistent toolbar and a widget (DtExampleWidget). The toolbar handles saving, loading, exporting, and importing the settings it controls, and the widget controls an example setting. The DtExampleWidget is implemented according to the humble dialog pattern, so its communication with the non-Qt parts of the application are controlled by a logic (DtExampleLogic) through an interface (DtExampleInterface).
The example settings are managed by the DtExampleSettingsManager, which is a rooted singleton that uses the DtExampleSettingsRecord to serialize the setting.
Settings
The DtExampleSettingsManager demonstrates how to set up a standard settings manager in VR-Vantage. By subclassing the DtBaseSettingsManager class, creation and loading of the default settings are automatically handled. As far as initializing your settings manager goes, the only thing that needs to be done is to provide a setting name, display name, and file extension to the constructor:
DtExampleSettingsManager::DtExampleSettingsManager( DtDe& de )
: DtBaseSettingsManager<DtExampleSettingsRecord>(
de, "Example", "Example Settings", "eorx" )
, myDummyVal(0)
{
}
The example setting is called dummyVal. It can be set or checked through the settings manager, and (through the autoSaveIfNecessary method), is automatically saved when it's changed if autosaving is enabled for the settings manager.
void DtExampleSettingsManager::setDummyVal(
int val )
{
signal_dummyValSet( val );
autoSaveIfNecessary();
}
int DtExampleSettingsManager::dummyVal() const
{
return myDummyVal;
}
The DtBaseSettingsManager class handles the details of saving and loading the settings files, and as such it is not necessary to provide any logic for saving or loading the settings (unless you need to implement some additional behavior specific to your settings).
The example settings manager is a rooted singleton, like most other manager classes in VR-Vantage. This means that there is one instance per display engine, so the class can act as a singleton but still allow multiple display engines in a single application. Instances are looked up in the DtDe, and lazily created if one is not found using the defaultManagerInstanceFunction:
DtExampleSettingsManager& DtExampleSettingsManager::instance( DtDe& de )
{
return defaultManagerInstanceFunction<DtExampleSettingsManager>( de, false );
}
The defaultManagerInstanceFunction requires that the settings manager be created prior to initialization of the De, so the settings manager needs to be instanced in the plugin initialization function:
DtExampleSettingsManager::instance(de);
Boxes
New dialogs are added to the GUI framework by writing a creator class for the dialog page and registering an instance of it with the DtQtPageAssembler. Dialog page creators should be defined using the DtPageCreatorTemplate template class:
The DtExamplePage is a GUI for managing the example setting. It inherits from DtPage, the base class for all dialog pages in VR-Vantage. It has a toolbar for saving and restoring settings, and a widget for changing the setting. The DtExamplePage connects these parts in its setupGui() function:
void DtExamplePage::setupGui()
{
QVBoxLayout* mainLayout = new QVBoxLayout( this );
mainLayout->setMargin( 0 );
myToolbar = new DtPersistenceToolbarWidget( myDe, this );
myToolbar->setPersistentStateName( "Example Settings" );
mainLayout->addWidget( myToolbar );
myWidget = new DtExampleWidget( this );
mainLayout->addWidget( myWidget );
mainLayout->addStretch( 1 );
}
In accordance with the humble dialog pattern, the widget provides a GUI only, and the logic behind it is handled by a separate logic class. The logic is only active when the dialog page is, so the page's activate and deactivate methods are responsible for creating and destroying the logic:
void DtExamplePage::activate()
{
if ( ! myLogic )
{
myLogic = new DtExampleLogic( myDe, *myWidget, *myToolbar );
}
}
void DtExamplePage::deactivate()
{
delete myLogic;
myLogic = 0;
}
The DtExamplePage is added to its parent dialog (also known as a Page Collection) in the example plugin's initialization method. The dialog (Page Collection) is created in the DtVrvApplication's page configuration, then the page is added to it. The MasterMode specification in the following function call means that the dialog page will only be present when the application is run in master mode:
igApp->masterModePageConfiguration().addPageCollection(
"DtExampleDialog",DtUnicode::fromAscii("Example Dialog"),
DtPageConfiguration::Dialog,true,"DtExamplePage");
igApp->masterModePageConfiguration().addPagePath(
The example widget communicates with its logic through an interface, DtExampleInterface:
{
public:
virtual void setInt( int val ) = 0;
boost::signal<void ( int )> signal_intChanged;
};
The DtExampleLogic drives both the persistent toolbar and the settings GUI. Its responsibilities are sending up-to-date settings to the DtExampleWidget, and acting on signals from the GUIs. If there were a way of changing the example setting outside of the dialog page, for example with a toolbar button, it would also be necessary for the logic to track those changes and keep the DtExampleWidget up to date. When the setting is changed in the GUI, the widget emits a boost signal:
connect( myIntSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(slot_onIntChanged()) );
void DtExampleWidget::slot_onIntChanged()
{
signal_intChanged( myIntSpinBox->value() );
}
which the DtExampleLogic connects to in its constructor
manageConnection( myInterface.signal_intChanged.connect(
boost::bind(
&DtExampleLogic::slot_onIntChanged, this, _1 ) ) );
and responds by changing the setting in the DtExampleSettingsManager.
void DtExampleLogic::slot_onIntChanged( int val )
{
DtExampleSettingsManager::instance(myDe).setDummyVal( val );
}
When the DtExampleLogic is created, it sends the current settings to the GUI through the DtExampleInterface
void DtExampleLogic::sendSettingsToGui()
{
int dummyVal = DtExampleSettingsManager::instance(myDe).dummyVal();
myInterface.setInt( dummyVal );
}
and it also sends settings to the GUI when they are loaded with the persistent toolbar
void DtExampleLogic::on_importFilePathChosen(
const std::string& filePath )
{
DtExampleSettingsManager::instance(myDe).importSettings( filePath );
sendSettingsToGui();
}
void DtExampleLogic::settingsRestored(
const DtSettingsBackup*
b )
{
if ( b->backupClassType() == "Example" )
{
sendSettingsToGui();
}
}
Building the Example
VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.
Running the Example
This example is a plug-in. You can run it by running ./bin64/exampleDialogPage_stealth.bat (on Windows) or ./bin64/exampleDialogPage_stealth.sh (on Linux). For more information about running examples, please see Running Applications and Examples.
Example Source Files
ElementInspectorPage.h
#pragma once
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLEDIALOGPAGE
namespace makVrv
{
class DtDe;
namespace vrvExampleDialogPagePlugin
{
}
}
ElementInspectorPage.cxx
#pragma once
#ifdef _WIN32
# ifdef EXAMPLEDIALOGPAGE_EXPORTS
# define DT_DLL_EXAMPLEDIALOGPAGE __declspec ( dllexport )
# else
# define DT_DLL_EXAMPLEDIALOGPAGE __declspec ( dllimport )
# endif
#else
# define DT_DLL_EXAMPLEDIALOGPAGE
#endif
exampleDisplayUnitsPluginInit.cxx
{
return true;
}
namespace makVrv
{
namespace vrvExampleDialogPagePlugin
{
{
try
{
if ( igApp )
{
}
}
DtCATCH_AND_PROPAGATE( DtCorruptedState )
}
}
}
DtExampleInterface.h
#pragma once
namespace makVrv
{
{
public:
virtual void setInt( int val ) = 0;
boost::signal<void ( int )> signal_intChanged;
};
}
DtExampleLogic.cxx
#include <boost/bind.hpp>
namespace makVrv
{
DtPersistenceControlsInterface& pIFace )
: DtSignalConnectionManager()
, myDe( de )
, myInterface( iFace )
, myPersistenceInterface( pIFace )
{
sendSettingsToGui();
manageConnection( myInterface.signal_intChanged.connect(
boost::bind(
&DtExampleLogic::slot_onIntChanged, this, _1 ) ) );
manageConnection( myPersistenceInterface.signal_export.connect(
manageConnection( myPersistenceInterface.signal_import.connect(
manageConnection( myPersistenceInterface.signal_importFilenameChosen.connect(
boost::bind( &DtExampleLogic::on_importFilePathChosen,
this, _1 ) ) );
manageConnection( myPersistenceInterface.signal_exportFilenameChosen.connect(
boost::bind( &DtExampleLogic::on_exportFilePathChosen,
this, _1 ) ) );
DtSharedSettingsBackupManagerSignaler& bmSignaler =
DtSharedSettingsBackupManagerSignaler::instance(
DtSharedSettingsManager::instance(myDe) );
manageConnection( bmSignaler.signal_restored.connect(
boost::bind(&DtExampleLogic::settingsRestored,
this, _1 ) ) );
myPersistenceInterface.setBackup(
DtExampleSettingsManager::instance(myDe).settingsBackup() );
}
DtExampleLogic::~DtExampleLogic()
{
}
void DtExampleLogic::sendSettingsToGui()
{
int dummyVal = DtExampleSettingsManager::instance(myDe).dummyVal();
myInterface.setInt( dummyVal );
}
void DtExampleLogic::slot_onIntChanged( int val )
{
DtExampleSettingsManager::instance(myDe).setDummyVal( val );
}
void DtExampleLogic::on_import()
{
DtDeSettings* settings =
DtDeSettingsManager::instance(myDe).findSettings( "Example" );
if ( settings )
{
myPersistenceInterface.queryImportFilePath( myDe, "Example Settings",
myDe.dePathConfiguration().settingsPath(), settings->extension() );
}
}
void DtExampleLogic::on_export()
{
DtDeSettings* settings =
DtDeSettingsManager::instance(myDe).findSettings( "Example" );
if ( settings )
{
myPersistenceInterface.queryExportFilePath( myDe, "Example Settings",
myDe.dePathConfiguration().settingsPath(), settings->extension() );
}
}
void DtExampleLogic::on_importFilePathChosen(
const std::string& filePath )
{
DtExampleSettingsManager::instance(myDe).importSettings( filePath );
sendSettingsToGui();
}
void DtExampleLogic::on_exportFilePathChosen(
const std::string& filePath )
{
DtExampleSettingsManager::instance(myDe).exportSettings( filePath );
}
void DtExampleLogic::settingsRestored( const DtSettingsBackup* b )
{
if ( b->backupClassType() == "Example" )
{
sendSettingsToGui();
}
}
}
DtExampleLogic.h
#pragma once
namespace makVrv
{
class DtDe;
class DtSettingsBackup;
class DtExampleInterface;
class DtPersistenceControlsInterface;
: private DtSignalConnectionManager
{
public:
DtExampleLogic( DtDe& de, DtExampleInterface& iFace,
DtPersistenceControlsInterface& pIFace );
virtual ~DtExampleLogic();
virtual void sendSettingsToGui();
void slot_onIntChanged( int val );
virtual void on_import();
virtual void on_export();
virtual void on_importFilePathChosen(
const std::string& filePath );
virtual void on_exportFilePathChosen(
const std::string& filePath );
virtual void settingsRestored( const DtSettingsBackup* b );
protected:
DtDe& myDe;
DtExampleInterface& myInterface;
DtPersistenceControlsInterface& myPersistenceInterface;
};
}
DtExampleDialogMenu.cxx
#include <QtWidgets/QMenu>
namespace makVrv
{
: DtMenu( de, std::
string(
"DtExampleDialogMenu") )
{
}
DtExampleDialogMenu::~DtExampleDialogMenu()
{
}
QMenu* DtExampleDialogMenu::createMenu( DtDe&,
QWidget* parent )
{
QMenu* menu =
new QMenu( QMenu::tr(
"Examples"), parent );
return menu;
}
DtExampleSettingsMenuItem::DtExampleSettingsMenuItem( DtDe& de )
: DtMenuItem( std::
string(
"DtExampleSettingsMenuItem") )
, myDe( de )
{
}
DtExampleSettingsMenuItem::~DtExampleSettingsMenuItem()
{
}
QAction* DtExampleSettingsMenuItem::createAction( DtDe&,
QWidget* parent )
{
action->setText( DtMenuItem::tr("Example Settings...") );
action->setIcon( QIcon(":/icons/exampleIcon.png") );
return action;
}
void DtExampleSettingsMenuItem::on_triggered()
{
DtPageCollectionManager::instance(myDe).showCollection( "DtExampleDialog" );
}
}
DtExampleDialogMenu.h
#pragma once
namespace makVrv
{
{
public:
DtExampleDialogMenu( DtDe& de );
virtual ~DtExampleDialogMenu();
};
: public DtMenuItem
{
public:
DtExampleSettingsMenuItem( DtDe& de );
virtual ~DtExampleSettingsMenuItem();
protected:
virtual void on_triggered();
protected:
DtDe& myDe;
};
}
DtExamplePage.cxx
#include <QtWidgets/QVBoxLayout>
namespace makVrv
{
: DtPage( de, parent, f )
, myWidget( 0 )
, myLogic( 0 )
{
setupGui();
}
DtExamplePage::~DtExamplePage()
{
delete myLogic;
myLogic = 0;
}
void DtExamplePage::setupGui()
{
QVBoxLayout* mainLayout = new QVBoxLayout( this );
mainLayout->setMargin( 0 );
myToolbar = new DtPersistenceToolbarWidget( myDe, this );
myToolbar->setPersistentStateName( "Example Settings" );
mainLayout->addWidget( myToolbar );
myWidget = new DtExampleWidget( this );
mainLayout->addWidget( myWidget );
mainLayout->addStretch( 1 );
}
void DtExamplePage::activate()
{
if ( ! myLogic )
{
myLogic = new DtExampleLogic( myDe, *myWidget, *myToolbar );
}
}
void DtExamplePage::deactivate()
{
delete myLogic;
myLogic = 0;
}
QIcon DtExamplePage::icon()
{
return QIcon (":/icons/exampleIcon.png");
}
QString DtExamplePage::title()
{
return DtExamplePage::tr("Example Page");
}
const std::string& DtExamplePage::pageClassName()
const
{
return thePageClassName();
}
{
return theClassName;
}
}
DtExamplePage.h
#pragma once
namespace makVrv
{
class DtDe;
class DtExampleWidget;
class DtExampleLogic;
class DtPersistenceToolbarWidget;
{ Q_OBJECT;
public:
DtExamplePage( DtDe& de,
QWidget* parent = 0,
Qt::WindowFlags
f = Qt::Widget );
virtual ~DtExamplePage();
virtual QIcon icon();
virtual QString title();
protected:
void setupGui();
virtual void activate();
virtual void deactivate();
protected:
DtExampleWidget* myWidget;
DtPersistenceToolbarWidget* myToolbar;
DtExampleLogic* myLogic;
};
}
DtExampleSettingsManager.cxx
namespace makVrv
{
{
return defaultManagerInstanceFunction<DtExampleSettingsManager>( de, false );
}
: DtBaseSettingsManager<DtExampleSettingsRecord>(
de, "Example", "Example Settings", "eorx" )
, myDummyVal(0)
{
}
DtExampleSettingsManager::~DtExampleSettingsManager()
{
}
void DtExampleSettingsManager::setDummyVal( int val )
{
signal_dummyValSet( val );
autoSaveIfNecessary();
}
int DtExampleSettingsManager::dummyVal() const
{
return myDummyVal;
}
void DtExampleSettingsManager::setFromRecord( const DtExampleSettingsRecord& rec )
{
setDummyVal( rec.dummyVal() );
}
void DtExampleSettingsManager::getRecord( DtExampleSettingsRecord& rec ) const
{
rec.setDummyVal( dummyVal() );
}
}
DtExampleSettingsManager.h
#pragma once
#include <boost/signals.hpp>
namespace makVrv
{
class DtDe;
class DtRecordSettingsBackupInterface;
: public DtBaseSettingsManager<DtExampleSettingsRecord>
{
public:
static DtExampleSettingsManager& instance( DtDe& de );
virtual ~DtExampleSettingsManager();
virtual void setDummyVal( int val );
virtual int dummyVal() const;
boost::signal<void ( int )> signal_dummyValSet;
void setFromRecord( const DtExampleSettingsRecord& rec );
void getRecord( DtExampleSettingsRecord& rec ) const;
protected:
template <typename ManagerClass>
template <typename ManagerClass>
DtExampleSettingsManager( DtDe& );
protected:
int myDummyVal;
};
}
DtExampleSettingsRecord.cxx
namespace makVrv
{
: myDummyVal( 77 )
{
}
DtExampleSettingsRecord::DtExampleSettingsRecord( const DtExampleSettingsRecord& orig)
: myDummyVal( orig.myDummyVal )
{
}
DtExampleSettingsRecord& DtExampleSettingsRecord::operator=( const DtExampleSettingsRecord& orig )
{
if ( this != &orig )
{
myDummyVal = orig.myDummyVal;
}
return *this;
}
DtExampleSettingsRecord::~DtExampleSettingsRecord()
{
}
void DtExampleSettingsRecord::setDummyVal(int val)
{
}
int DtExampleSettingsRecord::dummyVal() const
{
return myDummyVal;
}
}
DtExampleSettingsRecord.h
#pragma once
#include <vector>
namespace makVrv
{
{
public:
DtExampleSettingsRecord();
DtExampleSettingsRecord( const DtExampleSettingsRecord& orig );
DtExampleSettingsRecord& operator = ( const DtExampleSettingsRecord& orig );
virtual ~DtExampleSettingsRecord();
virtual void setDummyVal(int val);
virtual int dummyVal() const;
protected:
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP( myDummyVal );
}
protected:
int myDummyVal;
};
}
DtExampleWidget.cxx
namespace makVrv
{
, Ui::DtExampleWidgetUI()
{
setupUi( this );
connect( myIntSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(slot_onIntChanged()) );
}
DtExampleWidget::~DtExampleWidget()
{
}
void DtExampleWidget::slot_onIntChanged()
{
signal_intChanged( myIntSpinBox->value() );
}
void DtExampleWidget::setInt( int val )
{
bool restore = myIntSpinBox->blockSignals( true );
myIntSpinBox->setValue( val );
myIntSpinBox->blockSignals( restore );
}
}
DtExampleWidget.h
#pragma once
#include <QtWidgets/QWidget>
namespace makVrv
{
, public DtExampleInterface
{ Q_OBJECT;
public:
DtExampleWidget(
QWidget* parent = 0, Qt::WindowFlags f = Qt::Widget );
virtual ~DtExampleWidget();
virtual void setInt( int val );
public slots:
void slot_onIntChanged();
protected:
};
}