From 1dfa11061499299ad5c70ba3e5c2d0a249919d63 Mon Sep 17 00:00:00 2001 From: Joseph Mirabel <jmirabel@laas.fr> Date: Wed, 23 May 2018 11:42:24 +0200 Subject: [PATCH] In BodyTreeWidget, show properties of nodes. --- include/gepetto/gui/bodytreewidget.hh | 8 +- include/gepetto/gui/tree-item.hh | 23 +++- include/gepetto/gui/ui/mainwindow.ui | 32 +---- src/gui/bodytreewidget.cc | 30 +++-- src/gui/mainwindow.cc | 2 +- src/gui/tree-item.cc | 177 ++++++++++++++++++++++---- src/gui/windows-manager.cc | 2 + 7 files changed, 200 insertions(+), 74 deletions(-) diff --git a/include/gepetto/gui/bodytreewidget.hh b/include/gepetto/gui/bodytreewidget.hh index be9c6f9..20b0bcc 100644 --- a/include/gepetto/gui/bodytreewidget.hh +++ b/include/gepetto/gui/bodytreewidget.hh @@ -58,8 +58,8 @@ 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 () {} @@ -132,10 +132,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/tree-item.hh b/include/gepetto/gui/tree-item.hh index af0cc5a..2f40e41 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,23 @@ 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; + 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 5fafe64..605eaed 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/src/gui/bodytreewidget.cc b/src/gui/bodytreewidget.cc index dd62091..1acd499 100644 --- a/src/gui/bodytreewidget.cc +++ b/src/gui/bodytreewidget.cc @@ -82,12 +82,12 @@ static void addSlider (QToolBox* tb, QString title, QObject* receiver, const cha 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 +97,12 @@ 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 () @@ -177,6 +171,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 +195,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); diff --git a/src/gui/mainwindow.cc b/src/gui/mainwindow.cc index 6907c93..dfb3676 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 47031ec..0ac9781 100644 --- a/src/gui/tree-item.cc +++ b/src/gui/tree-item.cc @@ -26,21 +26,164 @@ 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); + int indexSelected = 0; + for (std::size_t i = 0; i < enumMeta->values.size(); ++i) + { + qDebug() << enumMeta->names[i].c_str() << ":" << enumMeta->values[i]; + cb->addItem(enumMeta->names[i].c_str(), enumMeta->values[i]); + if (value == enumMeta->values[i]) indexSelected = i; + } + cb->setCurrentIndex(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; + } + BodyTreeItem::BodyTreeItem(QObject *parent, graphics::NodePtr_t node) : QObject (parent), QStandardItem (QString (node->getID().c_str())), - node_ (node), - vmMapper_ (), - vizMapper_ () + 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 { + qDebug() << "Unhandled property" << name << "of type" << prop->type().c_str() << "."; + } + if (field != NULL) { + field->setProperty("propertyName", name); + l->addRow(name + ':', field); + } + } + 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()) { + qDebug() << "Set property" << nameVariant; + std::string name = nameVariant.toString().toStdString(); + boost::mutex::scoped_lock lock (MainWindow::instance()->osg()->osgFrameMutex()); + node_->setProperty<T>(name, value); + } + } + } + + 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 + { + qDebug() << "Set property" << float(value); + setProperty (QObject::sender(), float(value)); + } + + BodyTreeItem::~BodyTreeItem() + { + if (propertyEditors_->parent() != NULL) + delete propertyEditors_; + } + QStandardItem* BodyTreeItem::clone() const { return new BodyTreeItem (QObject::parent(), node_); @@ -68,28 +211,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 7e1b0f0..7d3dac2 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); } } -- GitLab