diff --git a/doc/opengl_primitives.png b/doc/opengl_primitives.png deleted file mode 100644 index 1121812ad648f4cff422bffb0e2592d21b17406b..0000000000000000000000000000000000000000 Binary files a/doc/opengl_primitives.png and /dev/null differ diff --git a/idl/gepetto/viewer/graphical-interface.idl b/idl/gepetto/viewer/graphical-interface.idl index 609856d053572fe7f3ec01e28624320d5950c546..06a8fc75ce75df6dd0f2303683f5ce99e640f1f2 100644 --- a/idl/gepetto/viewer/graphical-interface.idl +++ b/idl/gepetto/viewer/graphical-interface.idl @@ -182,7 +182,7 @@ typedef sequence<Transform> TransformSeq; boolean setCurvePoints(in string curveName, in PositionSeq pos) raises (Error); /// \param mode The list of possible GL modes is provided in - /// WindowsManager::setCurveMode. + /// graphics::WindowsManager::setCurveMode. /// From the GL modes, remove "GL_" and put it lower case. boolean setCurveMode (in string curveName, in string mode) raises (Error); diff --git a/include/gepetto/gui/bodytreewidget.hh b/include/gepetto/gui/bodytreewidget.hh index be9c6f9ef31ef0dff233f598ad8eef698ad6609a..a75411935fd1e5f9fc9ef3e17ea9f53de7fed44e 100644 --- a/include/gepetto/gui/bodytreewidget.hh +++ b/include/gepetto/gui/bodytreewidget.hh @@ -17,23 +17,6 @@ #ifndef GEPETTO_GUI_BODYTREEWIDGET_HH #define GEPETTO_GUI_BODYTREEWIDGET_HH -// This does not work because of qt meta-object compiler -#define GEPETTO_GUI_BODYTREE_DECL_FEATURE(func, ArgType) \ - public slots: \ - void func (ArgType arg) -#define GEPETTO_GUI_BODYTREE_IMPL_FEATURE(func, ArgType, OutType, WindowsManagerFunc) \ - void BodyTreeWidget::func (ArgType arg) { \ - WindowsManagerPtr_t wsm = MainWindow::instance()->osg(); \ - foreach (const QModelIndex& index, view_->selectionModel ()->selectedIndexes ()) { \ - const BodyTreeItem *item = dynamic_cast <const BodyTreeItem*> \ - (model_->itemFromIndex (index)); \ - if (item) wsm->WindowsManagerFunc (item->node()->getID(), \ - convertTo<OutType>::from(arg)); \ - else \ - qDebug() << model_->itemFromIndex(index)->text() << "is not a BodyTreeItem"; \ - } \ - } - #include <QWidget> #include <QTreeView> #include <QToolBox> @@ -58,15 +41,11 @@ namespace gepetto { /// Init the widget. /// \param view tree view to display. - /// \param toolBox menu in the window - void init(QTreeView *view, QToolBox* toolBox); + /// \param propertyArea menu in the window + void init(QTreeView *view, QWidget *propertyArea); virtual ~BodyTreeWidget () {} - /// Display the value in the slider. - /// \param alpha alpha value to convert - void changeAlphaValue(const float& alpha); - /// Get the body tree view. QTreeView* view (); @@ -95,26 +74,6 @@ namespace gepetto { /// Get selected bodies QList<BodyTreeItem*> selectedBodies() const; - /// Set the transparency of currently selected body. - /// \param value value of the slider to convert - void setTransparency(int value); - - /// Set the visibility mode of currently selected body. - /// \param arg visibility mode - void setVisibilityMode (QString arg); - - /// Set the wireframe mode of currently selected body. - /// \param arg wireframe mode - void setWireFrameMode (QString arg); - - /// Set the color of currently selected body. - /// \param color new color of the body - void setColor (QColor color); - - /// Set the scale of currently selected body. - /// \param scale new scale of the body - void setScale (int scale); - /// \} protected slots: @@ -132,10 +91,12 @@ namespace gepetto { /// is updated. void handleSelectionEvent (const SelectionEvent* event); + void updatePropertyArea (BodyTreeItem* item); + QTreeView* view_; QStandardItemModel* model_; WindowsManagerPtr_t osg_; - QToolBox* toolBox_; + QWidget* propertyArea_; }; } } diff --git a/include/gepetto/gui/dialog/pluginmanagerdialog.hh b/include/gepetto/gui/dialog/pluginmanagerdialog.hh index fb5cf22558a8e03a68d86722fb65318ebfef1877..07bd30ab2dad5f274f7a8334aa553c65f1109fd2 100644 --- a/include/gepetto/gui/dialog/pluginmanagerdialog.hh +++ b/include/gepetto/gui/dialog/pluginmanagerdialog.hh @@ -67,12 +67,21 @@ namespace gepetto { void clearPlugins (); + bool declarePyPlugin (const QString& name); + + bool loadPyPlugin (const QString& name); + + bool unloadPyPlugin (const QString& name); + + void clearPyPlugins (); + private: template <typename Interface> static const Interface* const_instance_cast (const QPluginLoader* pl); QMap <QString, QPluginLoader*> plugins_; static QList <QDir> pluginDirs_; + QMap <QString, QString> pyplugins_; }; class PluginManagerDialog : public QDialog diff --git a/include/gepetto/gui/fwd.hh b/include/gepetto/gui/fwd.hh index 1f08e99a8f587ca55d6ac0129ce933315f6eeffe..4b6c73bf3bd55280d6acee6cba602b81f3a969d1 100644 --- a/include/gepetto/gui/fwd.hh +++ b/include/gepetto/gui/fwd.hh @@ -17,6 +17,8 @@ #ifndef GEPETTO_GUI_FWD_HH #define GEPETTO_GUI_FWD_HH +#include <vector> + #include <gepetto/viewer/macros.h> #include <gepetto/gui/config-dep.hh> @@ -27,6 +29,7 @@ namespace gepetto { class PickHandler; class BodyTreeWidget; class BodyTreeItem; + typedef std::vector<BodyTreeItem*> BodyTreeItems_t; class ShortcutFactory; class SelectionHandler; class SelectionEvent; diff --git a/include/gepetto/gui/tree-item.hh b/include/gepetto/gui/tree-item.hh index af0cc5a58e70601a1c295e45365b729f8250ff3d..4380129ff5b887306ea71022e50ef7a0d9556a46 100644 --- a/include/gepetto/gui/tree-item.hh +++ b/include/gepetto/gui/tree-item.hh @@ -36,6 +36,7 @@ namespace gepetto { public: BodyTreeItem (QObject* parent, graphics::NodePtr_t node); + void initialize(); virtual QStandardItem* clone () const; @@ -49,7 +50,12 @@ namespace gepetto { void setParentGroup (const std::string& parent); - virtual ~BodyTreeItem() {}; + QWidget* propertyEditors () const + { + return propertyEditors_; + } + + virtual ~BodyTreeItem(); public: void attachToWindow (unsigned int windowID); @@ -64,12 +70,24 @@ namespace gepetto { void deleteLandmark (); QString text () const { return QStandardItem::text(); } + signals: + void requestInitialize(); + private slots: + void doInitialize(); + + void setBoolProperty (bool value) const; + void setIntProperty (int value) const; + void setStringProperty (const QString& value) const; + void setFloatProperty (const double& value) const; + void setColorProperty (const QColor& value) const; + private: + template <typename T> void setProperty(const QObject* sender, const T& value) const; + graphics::NodePtr_t node_; std::string parentGroup_; - QSignalMapper vmMapper_; - QSignalMapper vizMapper_; + QWidget* propertyEditors_; friend class VisibilityItem; }; diff --git a/include/gepetto/gui/ui/mainwindow.ui b/include/gepetto/gui/ui/mainwindow.ui index 5fafe64aa9fac7900688789b1ddc309af7a3aa32..605eaeda6fb82aa3d98b9a74c39716386f534507 100644 --- a/include/gepetto/gui/ui/mainwindow.ui +++ b/include/gepetto/gui/ui/mainwindow.ui @@ -37,7 +37,6 @@ <property name="styleSheet"> <string notr="true">image: url(:/img/gepetto.png);</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_5"/> </widget> <widget class="QMenuBar" name="menuBar"> <property name="geometry"> @@ -45,7 +44,7 @@ <x>0</x> <y>0</y> <width>754</width> - <height>20</height> + <height>27</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -146,38 +145,15 @@ <property name="widgetResizable"> <bool>true</bool> </property> - <widget class="QWidget" name="scrollAreaWidgetContents"> + <widget class="QWidget" name="propertyArea"> <property name="geometry"> <rect> <x>0</x> <y>0</y> - <width>254</width> - <height>127</height> + <width>252</width> + <height>133</height> </rect> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QToolBox" name="toolBox"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="Info"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>238</width> - <height>83</height> - </rect> - </property> - <attribute name="label"> - <string>Transparency</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout"/> - </widget> - </widget> - </item> - </layout> </widget> </widget> </widget> diff --git a/include/gepetto/gui/windows-manager.hh b/include/gepetto/gui/windows-manager.hh index 0abaded93fd0f1c33c8abde9e0e2223f0bbb8659..0870fb5f3417c915a9235a4e9a64340f7cfd0e25 100644 --- a/include/gepetto/gui/windows-manager.hh +++ b/include/gepetto/gui/windows-manager.hh @@ -57,6 +57,8 @@ namespace gepetto { bool removeFromGroup (const std::string& nodeName, const std::string& groupName); bool deleteNode (const std::string& nodeName, bool all); + BodyTreeItems_t bodyTreeItems (const std::string& name) const; + public slots: int createWindow(QString windowName); protected: @@ -66,7 +68,6 @@ namespace gepetto { virtual void addGroup(const std::string& groupName, GroupNodePtr_t group, GroupNodePtr_t parent); private: - typedef std::vector<BodyTreeItem*> BodyTreeItems_t; typedef std::pair<BodyTreeItems_t, bool> BodyTreeItemsAndGroup_t; typedef std::map<std::string, BodyTreeItemsAndGroup_t> BodyTreeItemMap_t; BodyTreeWidget* bodyTree_; diff --git a/include/gepetto/viewer/corba/windows-manager.hh b/include/gepetto/viewer/corba/windows-manager.hh index a2de9af3f2647d93e9a31a63b8ebc584f0775984..09fb091f5cd2228b899c69e31fc0c8c85a42d755 100644 --- a/include/gepetto/viewer/corba/windows-manager.hh +++ b/include/gepetto/viewer/corba/windows-manager.hh @@ -181,7 +181,7 @@ namespace graphics { virtual bool setCurvePoints(const std::string& curveName, const Vec3ArrayPtr_t& pos); - /// \image html opengl_primitives.png + /// \param mode See LeafNodeLine::setMode for possible values virtual bool setCurveMode (const std::string& curveName, const GLenum mode); virtual bool setCurvePointsSubset (const std::string& curveName, const int first, const std::size_t count); virtual bool setCurveLineWidth (const std::string& curveName, const float& width); diff --git a/plugins/pyqcustomplot/decorator.hh b/plugins/pyqcustomplot/decorator.hh index b2ef2341bf087abbad4144c0621ade4491bdebf5..5cc8ce48561524b1188a6f4feed16ae0f41681d7 100644 --- a/plugins/pyqcustomplot/decorator.hh +++ b/plugins/pyqcustomplot/decorator.hh @@ -121,6 +121,10 @@ class QCustomPlotDecorator : public QObject { g->addData(keys,values); } + void addData (QCPGraph* g, const double &key, const double &value) + { + g->addData(key,value); + } void clearData (QCPGraph* o) { o->clearData (); } /// \} diff --git a/src/gui/bodytreewidget.cc b/src/gui/bodytreewidget.cc index dd62091282543ac2cf1063d4951affbed557e992..785f4f18d27093fd677684ebb1d5e3ac968a9cc8 100644 --- a/src/gui/bodytreewidget.cc +++ b/src/gui/bodytreewidget.cc @@ -29,65 +29,14 @@ #include <QHBoxLayout> #include <QApplication> -static void addSelector (QToolBox* tb, QString title, QStringList display, QStringList command, - QObject* receiver, const char* slot) { - QWidget* newW = new QWidget(); - newW->setObjectName(title); - QSignalMapper* mapper = new QSignalMapper (tb); - QHBoxLayout* layout = new QHBoxLayout(newW); - layout->setSpacing(6); - layout->setContentsMargins(11, 11, 11, 11); - layout->setObjectName(title + "_layout"); - for (int i = 0; i < display.size(); ++i) { - QPushButton* button = new QPushButton(display[i], newW); - button->setObjectName(title + "_button_" + display[i]); - layout->addWidget (button); - mapper->setMapping(button, command[i]); - QObject::connect (button, SIGNAL(clicked(bool)), mapper, SLOT(map())); - } - receiver->connect (mapper, SIGNAL(mapped(QString)), slot); - tb->addItem(newW, title); -} - -static void addColorSelector (QToolBox* tb, QString title, QObject* receiver, const char* slot) { - QWidget* newW = new QWidget(); - newW->setObjectName(title); - QHBoxLayout* layout = new QHBoxLayout(); - newW->setLayout(layout); - layout->setSpacing(6); - layout->setContentsMargins(11, 11, 11, 11); - layout->setObjectName(title + "_layout"); - QPushButton* button = new QPushButton("Select color", newW); - button->setObjectName(title + "_buttonSelect"); - layout->addWidget (button); - - QColorDialog* colorDialog = new QColorDialog(newW); - colorDialog->setObjectName(title + "_colorDialog"); - colorDialog->setOption(QColorDialog::ShowAlphaChannel, true); - - colorDialog->connect(button, SIGNAL(clicked()), SLOT(open())); - receiver->connect (colorDialog, SIGNAL(colorSelected(QColor)), slot); - tb->addItem(newW, title); -} - -static void addSlider (QToolBox* tb, QString title, QObject* receiver, const char* slot) { - QSlider* slider = new QSlider (Qt::Horizontal); - slider->setMinimum(0); - slider->setMaximum(100); - slider->setObjectName(title); - - receiver->connect (slider, SIGNAL(valueChanged(int)), slot); - tb->addItem(slider, title); -} - namespace gepetto { namespace gui { - void BodyTreeWidget::init(QTreeView* view, QToolBox *toolBox) + void BodyTreeWidget::init(QTreeView* view, QWidget *propertyArea) { MainWindow* main = MainWindow::instance(); osg_ = main->osg(); view_ = view; - toolBox_ = toolBox; + propertyArea_ = propertyArea; model_ = new QStandardItemModel (this); view_->setModel(model_); view_->setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -97,18 +46,10 @@ namespace gepetto { SIGNAL (currentChanged(QModelIndex,QModelIndex)), SLOT (currentChanged(QModelIndex,QModelIndex))); - toolBox_->removeItem(0); - addSlider(toolBox_, "Transparency", this, SLOT(setTransparency(int))); - addSelector (toolBox_, "Visibility", - QStringList () << "On" << "Always on top" << "Off", - QStringList () << "ON" << "ALWAYS_ON_TOP" << "OFF", - this, SLOT(setVisibilityMode(QString))); - addSelector (toolBox_, "Wireframe mode", - QStringList () << "Fill" << "Both" << "Wireframe", - QStringList () << "FILL" << "FILL_AND_WIREFRAME" << "WIREFRAME", - this, SLOT(setWireFrameMode(QString))); - addColorSelector(toolBox_, "Color", this, SLOT(setColor(QColor))); +/* addSlider(toolBox_, "Scale", this, SLOT(setScale(int))); +*/ + propertyArea_->setLayout (new QVBoxLayout); } QTreeView* BodyTreeWidget::view () @@ -118,24 +59,19 @@ namespace gepetto { void BodyTreeWidget::selectBodyByName(const QString bodyName) { - QList<QStandardItem*> matches; - if (!bodyName.isEmpty() && !bodyName.isNull()) { - matches = model_->findItems(bodyName, Qt::MatchFixedString - | Qt::MatchCaseSensitive - | Qt::MatchRecursive); - } - if (matches.empty()) { - qDebug () << "Body" << bodyName << "not found."; - view_->clearSelection(); - } else { - view_->setCurrentIndex(matches.first()->index()); - } + qDebug () << "Use std::string instead of QString"; + return selectBodyByName (bodyName.toStdString()); } void BodyTreeWidget::selectBodyByName (const std::string& bodyName) { - qDebug () << "Use QString instead of std::string"; - return selectBodyByName (QString::fromStdString (bodyName)); + BodyTreeItems_t bodies = osg_->bodyTreeItems (bodyName); + if (bodies.empty()) { + qDebug () << "Body" << bodyName.c_str() << "not found."; + view_->clearSelection(); + } else { + view_->setCurrentIndex(bodies[0]->index()); + } } void BodyTreeWidget::handleSelectionEvent (const SelectionEvent* event) @@ -143,23 +79,25 @@ namespace gepetto { disconnect (view_->selectionModel(), SIGNAL (currentChanged(QModelIndex,QModelIndex)), this, SLOT (currentChanged(QModelIndex,QModelIndex))); + BodyTreeItem* item = NULL; if (event->node()) { - QList<QStandardItem*> matches; - matches = model_->findItems(event->nodeName(), Qt::MatchFixedString - | Qt::MatchCaseSensitive - | Qt::MatchRecursive); + BodyTreeItems_t matches = osg_->bodyTreeItems(event->node()->getID()); + if (matches.empty()) view_->clearSelection(); else { + item = matches[0]; if (event->modKey() == Qt::ControlModifier) - view_->selectionModel()->setCurrentIndex - (matches.first()->index(), + view_->selectionModel()->setCurrentIndex (item->index(), QItemSelectionModel::Toggle); else - view_->selectionModel()->select(matches.first()->index(), QItemSelectionModel::ClearAndSelect); + view_->selectionModel()->select (item->index(), + QItemSelectionModel::ClearAndSelect); + view_->scrollTo (matches[0]->index()); } } else view_->clearSelection(); + updatePropertyArea(item); connect (view_->selectionModel(), SIGNAL (currentChanged(QModelIndex,QModelIndex)), SLOT (currentChanged(QModelIndex,QModelIndex))); @@ -177,6 +115,19 @@ namespace gepetto { event->done(); } + void BodyTreeWidget::updatePropertyArea (BodyTreeItem* item) + { + QLayoutItem *child; + while ((child = propertyArea_->layout()->takeAt(0)) != 0) { + if (child->widget() != NULL) { + child->widget()->setParent(NULL); + } + } + if (item != NULL) { + propertyArea_->layout()->addWidget(item->propertyEditors()); + } + } + void BodyTreeWidget::currentChanged (const QModelIndex ¤t, const QModelIndex &/*previous*/) { @@ -188,6 +139,7 @@ namespace gepetto { qobject_cast <const QStandardItemModel*> (view_->model())->itemFromIndex(current) ); + updatePropertyArea(item); if (item) { SelectionEvent *event = new SelectionEvent(SelectionEvent::FromBodyTree, item->node(), QApplication::keyboardModifiers()); emitBodySelected(event); @@ -223,18 +175,5 @@ namespace gepetto { contextMenu.exec(view_->mapToGlobal(pos)); } } - - void BodyTreeWidget::changeAlphaValue(const float& alpha) - { - QSlider *tr = qobject_cast<QSlider *>(toolBox_->widget(0)); - - tr->setValue((int)alpha * 100); - } - - GEPETTO_GUI_BODYTREE_IMPL_FEATURE (setTransparency, int, int, setAlpha) - GEPETTO_GUI_BODYTREE_IMPL_FEATURE (setVisibilityMode, QString, std::string, setVisibility) - GEPETTO_GUI_BODYTREE_IMPL_FEATURE (setWireFrameMode, QString, std::string, setWireFrameMode) - GEPETTO_GUI_BODYTREE_IMPL_FEATURE (setColor, QColor, WindowsManager::Color_t, setColor) - GEPETTO_GUI_BODYTREE_IMPL_FEATURE (setScale, int, int, setScale) } } diff --git a/src/gui/dialog/pluginmanagerdialog.cc b/src/gui/dialog/pluginmanagerdialog.cc index 9d9d688f30ea82497cbe8e881f1d5d4914bb4f5b..822c7a84f16ab01da2469aa22238fc895ea10c8e 100644 --- a/src/gui/dialog/pluginmanagerdialog.cc +++ b/src/gui/dialog/pluginmanagerdialog.cc @@ -22,6 +22,7 @@ #include "gepetto/gui/plugin-interface.hh" #include "gepetto/gui/mainwindow.hh" +#include "gepetto/gui/pythonwidget.hh" #include <iostream> @@ -144,6 +145,69 @@ namespace gepetto { } } + bool PluginManager::declarePyPlugin(const QString &name) + { + if (!pyplugins_.contains(name)) { + if (name.endsWith (".py")) { + QFileInfo fi (name); + QString moduleName = fi.baseName(); + QString script; + if (fi.isAbsolute()) script = name; + else script = QDir::currentPath() + QDir::separator() + name; + pyplugins_[moduleName] = script; + } else + pyplugins_[name] = name; + return true; + } + qDebug () << "Python plugin" << name << "already declared."; + return false; + } + + bool PluginManager::loadPyPlugin(const QString &name) + { + if (!pyplugins_.contains(name)) { + qDebug () << "Python plugin" << name << "not declared."; + return false; + } + MainWindow* main = MainWindow::instance(); + const QString& pyfile = pyplugins_[name]; + +#if GEPETTO_GUI_HAS_PYTHONQT + PythonWidget* pw = main->pythonWidget(); + if (pyfile.endsWith (".py")) { + qDebug() << "Loading" << pyfile << "into module" << name; + pw->loadScriptPlugin (name, pyfile); + } else + pw->loadModulePlugin (name); + return true; +#else + main->logError ("gepetto-viewer-corba was compiled without GEPETTO_GUI_HAS_" + "PYTHONQT flag. Cannot not load Python plugin " + name); + return false; +#endif + } + + bool PluginManager::unloadPyPlugin(const QString &name) + { + MainWindow* main = MainWindow::instance(); +#if GEPETTO_GUI_HAS_PYTHONQT + PythonWidget* pw = main->pythonWidget(); + pw->unloadModulePlugin(name); + return true; +#else + main->logError ("gepetto-viewer-corba was compiled without GEPETTO_GUI_HAS_" + "PYTHONQT flag. Cannot not unload Python plugin " + name); + return false; +#endif + } + + void PluginManager::clearPyPlugins() + { + foreach (QString p, pyplugins_.keys()) { + unloadPyPlugin(p); + } + } + PluginManagerDialog::PluginManagerDialog(PluginManager *pm, QWidget *parent) : QDialog(parent), ui_(new ::Ui::PluginManagerDialog), @@ -240,8 +304,10 @@ namespace gepetto { version = ""; if (p.value ()->isLoaded ()) { PluginInterface* pi = qobject_cast <PluginInterface*> (p.value()->instance()); - name = pi->name(); - // version = pi->version(); + if (pi) { + name = pi->name(); + // version = pi->version(); + } } QIcon icon = pm_->icon (p.value()); diff --git a/src/gui/mainwindow.cc b/src/gui/mainwindow.cc index 6907c93faa561edc4940babb12bbe2345b6aca08..dfb3676824fe71e4586abfa10fc29ddcea04dc56 100644 --- a/src/gui/mainwindow.cc +++ b/src/gui/mainwindow.cc @@ -61,7 +61,7 @@ namespace gepetto { // Setup the body tree view osgViewerManagers_ = WindowsManager::create(ui_->bodyTreeContent); - ui_->bodyTreeContent->init(ui_->bodyTree, ui_->toolBox); + ui_->bodyTreeContent->init(ui_->bodyTree, ui_->propertyArea); if (settings_->startGepettoCorbaServer) { osgServer_ = new CorbaServer (new ViewerServerProcess ( diff --git a/src/gui/tree-item.cc b/src/gui/tree-item.cc index 47031ec53421aedd71e98788d9cce7124a877074..e6717701e3dde8468f48921f1d2ddda4ba2b86f6 100644 --- a/src/gui/tree-item.cc +++ b/src/gui/tree-item.cc @@ -17,6 +17,9 @@ #include "gepetto/gui/tree-item.hh" #include <QDebug> +#include <QLineEdit> +#include <QColorDialog> +#include <QFormLayout> #include <gepetto/viewer/group-node.h> @@ -26,19 +29,196 @@ namespace gepetto { namespace gui { + QWidget* boolPropertyEditor (BodyTreeItem* bti, const graphics::PropertyPtr_t prop) + { + QCheckBox* cb = new QCheckBox; + bool value; + /* bool success = */ prop->get(value); + cb->setChecked(value); + if (prop->hasWriteAccess()) + bti->connect(cb, SIGNAL(toggled(bool)), SLOT(setBoolProperty(bool))); + else + cb->setEnabled(false); + return cb; + } + + QWidget* enumPropertyEditor (BodyTreeItem* bti, const graphics::PropertyPtr_t prop) + { + const graphics::EnumProperty::Ptr_t enumProp = boost::dynamic_pointer_cast<graphics::EnumProperty> (prop); + const graphics::MetaEnum* enumMeta = enumProp->metaEnum(); + + QComboBox* cb = new QComboBox; + int value; + /* bool success = */ enumProp->get(value); + std::size_t indexSelected = 0; + for (std::size_t i = 0; i < enumMeta->values.size(); ++i) + { + cb->addItem(enumMeta->names[i].c_str(), enumMeta->values[i]); + if (value == enumMeta->values[i]) indexSelected = i; + } + cb->setCurrentIndex((int)indexSelected); + if (prop->hasWriteAccess()) + bti->connect(cb, SIGNAL(currentIndexChanged(int)), SLOT(setIntProperty(int))); + else + cb->setEnabled(false); + return cb; + } + + QWidget* stringPropertyEditor (BodyTreeItem* bti, const graphics::PropertyPtr_t prop) + { + QLineEdit* le = new QLineEdit; + std::string value; + /* bool success = */ prop->get(value); + le->setText(QString::fromStdString(value)); + if (prop->hasWriteAccess()) + bti->connect(le, SIGNAL(textChanged(QString)), SLOT(setStringProperty(QString))); + else + le->setReadOnly(true); + return le; + } + + QWidget* floatPropertyEditor (BodyTreeItem* bti, const graphics::PropertyPtr_t prop) + { + QDoubleSpinBox* dsb = new QDoubleSpinBox; + float value; + /* bool success = */ prop->get(value); + dsb->setValue(value); + if (prop->hasWriteAccess()) + bti->connect(dsb, SIGNAL(valueChanged(double)), SLOT(setFloatProperty(double))); + else + dsb->setEnabled(false); + return dsb; + } + + QWidget* colorPropertyEditor (BodyTreeItem* bti, const graphics::PropertyPtr_t prop) + { + if (!prop->hasWriteAccess()) return NULL; + osgVector4 value; + /* bool success = */ prop->get(value); + QColor color; + color.setRgbF((qreal)value[0],(qreal)value[1],(qreal)value[2],(qreal)value[3]); + + QPushButton* button = new QPushButton("Select color"); + // Set icon for current color value + + /// Color dialog should be opened in a different place + QColorDialog* colorDialog = new QColorDialog(color, MainWindow::instance()); + colorDialog->setOption(QColorDialog::ShowAlphaChannel, true); + + colorDialog->setProperty("propertyName", QString::fromStdString(prop->name())); + colorDialog->connect(button, SIGNAL(clicked()), SLOT(open())); + bti->connect (colorDialog, SIGNAL(colorSelected(QColor)), SLOT(setColorProperty(QColor))); + + return button; + } + BodyTreeItem::BodyTreeItem(QObject *parent, graphics::NodePtr_t node) : QObject (parent), - QStandardItem (QString (node->getID().c_str())), - node_ (node), - vmMapper_ (), - vizMapper_ () + QStandardItem (QString::fromStdString (node->getID().substr(node->getID().find_last_of("/") + 1))), + node_ (node) { setEditable(false); - connect (&vmMapper_, SIGNAL (mapped (QString)), SLOT(setViewingMode(QString))); - connect (&vizMapper_, SIGNAL (mapped (QString)), SLOT(setVisibilityMode(QString))); - - const std::string & name = node->getID(); - QStandardItem::setText(name.substr(name.find_last_of("/") + 1).c_str()); + } + + void BodyTreeItem::initialize () + { + connect(this, SIGNAL(requestInitialize()), SLOT(doInitialize())); + emit requestInitialize(); + } + + void BodyTreeItem::doInitialize () + { + propertyEditors_ = new QWidget(); + BodyTreeWidget* bt = MainWindow::instance()->bodyTree(); + if (propertyEditors_->thread() != bt->thread()) + propertyEditors_->moveToThread(bt->thread()); + QFormLayout* l = new QFormLayout(propertyEditors_); + + l->addRow("Node name:", new QLabel (node_->getID().c_str())); + + const graphics::PropertyMap_t& props = node_->properties(); + for (graphics::PropertyMap_t::const_iterator _prop = props.begin(); + _prop != props.end(); ++_prop) + { + const graphics::PropertyPtr_t prop = _prop->second; + if (!prop->hasReadAccess()) continue; + + QString name = _prop->first.c_str(); + QWidget* field = NULL; + if (prop->type() == "enum") { + field = enumPropertyEditor(this, prop); + } else if (prop->type() == "bool") { + field = boolPropertyEditor(this, prop); + } else if (prop->type() == "string") { + field = stringPropertyEditor(this, prop); + } else if (prop->type() == "float") { + field = floatPropertyEditor(this, prop); + } else if (prop->type() == "osgVector4") { + if (name.contains ("color", Qt::CaseInsensitive)) { + field = colorPropertyEditor (this, prop); + } else { + field = NULL; + } + } + if (field != NULL) { + field->setProperty("propertyName", name); + l->addRow(name + ':', field); + } else { + qDebug() << "Unhandled property" << name << "of type" << prop->type().c_str() << "."; + } + } + disconnect(SIGNAL(requestInitialize())); + } + + template <typename T> + void BodyTreeItem::setProperty (const QObject* sender, const T& value) const + { + if (sender != NULL) { + QVariant nameVariant = sender->property("propertyName"); + if (nameVariant.isValid()) { + std::string name = nameVariant.toString().toStdString(); + boost::mutex::scoped_lock lock (MainWindow::instance()->osg()->osgFrameMutex()); + node_->setProperty<T>(name, value); + } else { + qDebug() << "Sender has no property propertyName" << sender; + } + } + } + + void BodyTreeItem::setBoolProperty (bool value) const + { + setProperty (QObject::sender(), value); + } + + void BodyTreeItem::setIntProperty (int value) const + { + setProperty (QObject::sender(), value); + } + + void BodyTreeItem::setStringProperty (const QString& value) const + { + setProperty (QObject::sender(), value.toStdString()); + } + + void BodyTreeItem::setFloatProperty (const double& value) const + { + setProperty (QObject::sender(), float(value)); + } + + void BodyTreeItem::setColorProperty (const QColor& value) const + { + osgVector4 c ( + (float)value.redF(), + (float)value.greenF(), + (float)value.blueF(), + (float)value.alphaF()); + setProperty (QObject::sender(), c); + } + + BodyTreeItem::~BodyTreeItem() + { + if (propertyEditors_->parent() != NULL) + delete propertyEditors_; } QStandardItem* BodyTreeItem::clone() const @@ -68,28 +248,6 @@ namespace gepetto { QAction* rfg = contextMenu->addAction (tr("Remove from group")); connect (rfg, SIGNAL (triggered()), SLOT (removeFromGroup ())); } - /// Viewing mode - QMenu* viewmode = contextMenu->addMenu(tr("Viewing mode")); - QAction* f = viewmode->addAction ("Fill"); - QAction* w = viewmode->addAction ("Wireframe"); - QAction* fw = viewmode->addAction ("Fill and Wireframe"); - vmMapper_.setMapping (f , QString ("FILL")); - vmMapper_.setMapping (w , QString ("WIREFRAME")); - vmMapper_.setMapping (fw, QString ("FILL_AND_WIREFRAME")); - connect (f , SIGNAL(triggered()), &vmMapper_, SLOT (map())); - connect (w , SIGNAL(triggered()), &vmMapper_, SLOT (map())); - connect (fw, SIGNAL(triggered()), &vmMapper_, SLOT (map())); - /// Visibility mode - QMenu* vizmode = contextMenu->addMenu(tr("Visibility mode")); - QAction* on = vizmode->addAction ("On"); - QAction* aot = vizmode->addAction ("Always on top"); - QAction* off = vizmode->addAction ("Off"); - vizMapper_.setMapping (on , QString ("ON")); - vizMapper_.setMapping (aot, QString ("ALWAYS_ON_TOP")); - vizMapper_.setMapping (off, QString ("OFF")); - connect (on , SIGNAL(triggered()), &vizMapper_, SLOT (map())); - connect (aot, SIGNAL(triggered()), &vizMapper_, SLOT (map())); - connect (off, SIGNAL(triggered()), &vizMapper_, SLOT (map())); } void BodyTreeItem::setParentGroup(const std::string &parent) diff --git a/src/gui/windows-manager.cc b/src/gui/windows-manager.cc index 7e1b0f0a285ac8a44abb7056e61306f3f7f6f93f..83a2d91922730eb89c2306537a1876b80be69167 100644 --- a/src/gui/windows-manager.cc +++ b/src/gui/windows-manager.cc @@ -73,6 +73,7 @@ namespace gepetto { nodeItemMap_[groupName].second = true; if (bti->thread() != bodyTree_->thread()) bti->moveToThread(bodyTree_->thread()); + bti->initialize(); bodyTree_->model()->appendRow(bti); } } @@ -87,6 +88,7 @@ namespace gepetto { bti->setParentGroup(groupName); if (bti->thread() != bodyTree_->thread()) bti->moveToThread(bodyTree_->thread()); + bti->initialize(); groups[i]->appendRow(bti); } } @@ -147,6 +149,14 @@ namespace gepetto { return ret; } + BodyTreeItems_t WindowsManager::bodyTreeItems (const std::string& name) const + { + BodyTreeItemMap_t::const_iterator _btis = nodeItemMap_.find(name); + if (_btis != nodeItemMap_.end()) + return _btis->second.first; + return BodyTreeItems_t(); + } + void WindowsManager::deleteBodyItem(const std::string& nodeName) { BodyTreeItemMap_t::iterator _nodes = nodeItemMap_.find(nodeName);