extensible TaskPanel

Provide TaskPanel::addSubPanel() to add new sub panels.
Each panel can be activated with an associated QToolButton.
Sub panels, derived from base class SubPanel, automatically load/save their config settings.
All settings are shown in GlobalSettingsWidget (renamed from TaskSettings).
This commit is contained in:
Robert Haschke 2019-02-11 02:07:28 +01:00
parent 6950cf2b8e
commit 1ce66c758b
6 changed files with 122 additions and 64 deletions

View File

@ -3,7 +3,7 @@ set(MOVEIT_LIB_NAME motion_planning_tasks_rviz_plugin)
qt_wrap_ui(UIC_FILES qt_wrap_ui(UIC_FILES
task_panel.ui task_panel.ui
task_view.ui task_view.ui
task_settings.ui global_settings.ui
) )
add_library(${MOVEIT_LIB_NAME} add_library(${MOVEIT_LIB_NAME}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>moveit_rviz_plugin::TaskSettings</class> <class>moveit_rviz_plugin::GlobalSettingsWidget</class>
<widget class="QWidget" name="moveit_rviz_plugin::TaskSettings"> <widget class="QWidget" name="moveit_rviz_plugin::GlobalSettingsWidget">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
@ -27,7 +27,7 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<layout class="QVBoxLayout" name="tab_settings_layout"> <layout class="QVBoxLayout" name="layout">
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
@ -44,14 +44,14 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QLabel" name="settings_view_label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>Settings</string> <string>Global Settings</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="rviz::PropertyTreeWidget" name="settings_view"/> <widget class="rviz::PropertyTreeWidget" name="view"/>
</item> </item>
</layout> </layout>
</item> </item>

View File

@ -87,15 +87,20 @@ TaskPanel::TaskPanel(QWidget* parent)
{ {
Q_D(TaskPanel); Q_D(TaskPanel);
d->tasks_widget = new TaskView(this); // sync checked tool button with displayed widget
d->settings_widget = new TaskSettings(this); connect(d->tool_buttons_group, static_cast<void(QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
layout()->addWidget(d->tasks_widget); d->stackedWidget, [d](int index) { d->stackedWidget->setCurrentIndex(index); });
layout()->addWidget(d->settings_widget); connect(d->stackedWidget, &QStackedWidget::currentChanged, d->tool_buttons_group,
connect(d->tasks_widget, SIGNAL(configChanged()), this, SIGNAL(configChanged())); [d](int index) { d->tool_buttons_group->button(index)->setChecked(true); });
// create sub widgets with corresponding tool buttons
addSubPanel(new TaskView(this, d->property_root), "Tasks View", QIcon(":/icons/tasks.png"));
d->stackedWidget->setCurrentIndex(0); // Tasks View is show by default
// settings widget should come last
addSubPanel(new GlobalSettingsWidget(this, d->property_root), "Global Settings", QIcon(":/icons/settings.png"));
connect(d->button_show_stage_dock_widget, SIGNAL(clicked()), this, SLOT(showStageDockWidget())); connect(d->button_show_stage_dock_widget, SIGNAL(clicked()), this, SLOT(showStageDockWidget()));
connect(d->button_show_settings, SIGNAL(toggled(bool)), d->settings_widget, SLOT(setVisible(bool)));
d->settings_widget->setVisible(d->button_show_settings->isChecked());
// if still undefined, this becomes the global instance // if still undefined, this becomes the global instance
if (singleton_.isNull()) if (singleton_.isNull())
@ -107,6 +112,24 @@ TaskPanel::~TaskPanel()
delete d_ptr; delete d_ptr;
} }
void TaskPanel::addSubPanel(SubPanel *w, const QString& title, const QIcon& icon)
{
Q_D(TaskPanel);
auto button = new QToolButton(w);
button->setToolTip(title);
button->setIcon(icon);
button->setCheckable(true);
int index = d->stackedWidget->count();
d->tool_buttons_layout->insertWidget(index, button);
d->tool_buttons_group->addButton(button, index);
d->stackedWidget->addWidget(w);
w->setWindowTitle(title);
connect(w, SIGNAL(configChanged()), this, SIGNAL(configChanged()));
}
void TaskPanel::incDisplayCount(rviz::WindowManagerInterface* window_manager) void TaskPanel::incDisplayCount(rviz::WindowManagerInterface* window_manager)
{ {
++display_count_; ++display_count_;
@ -132,7 +155,11 @@ TaskPanelPrivate::TaskPanelPrivate(TaskPanel *q_ptr)
: q_ptr(q_ptr) : q_ptr(q_ptr)
{ {
setupUi(q_ptr); setupUi(q_ptr);
tool_buttons_group = new QButtonGroup(q_ptr);
tool_buttons_group->setExclusive(true);
button_show_stage_dock_widget->setEnabled(bool(getStageFactory())); button_show_stage_dock_widget->setEnabled(bool(getStageFactory()));
button_show_stage_dock_widget->setToolTip(QStringLiteral("Show available stages"));
property_root = new rviz::Property("Global Settings");
} }
void TaskPanel::onInitialize() void TaskPanel::onInitialize()
@ -143,13 +170,19 @@ void TaskPanel::onInitialize()
void TaskPanel::save(rviz::Config config) const void TaskPanel::save(rviz::Config config) const
{ {
rviz::Panel::save(config); rviz::Panel::save(config);
d_ptr->tasks_widget->save(config.mapMakeChild("tasks_view")); for (int i=0; i < d_ptr->stackedWidget->count(); ++i) {
SubPanel* w = static_cast<SubPanel*>(d_ptr->stackedWidget->widget(i));
w->save(config.mapMakeChild(w->windowTitle()));
}
} }
void TaskPanel::load(const rviz::Config& config) void TaskPanel::load(const rviz::Config& config)
{ {
rviz::Panel::load(config); rviz::Panel::load(config);
d_ptr->tasks_widget->load(config.mapGetChild("tasks_view")); for (int i=0; i < d_ptr->stackedWidget->count(); ++i) {
SubPanel* w = static_cast<SubPanel*>(d_ptr->stackedWidget->widget(i));
w->load(config.mapGetChild(w->windowTitle()));
}
} }
void TaskPanel::showStageDockWidget() void TaskPanel::showStageDockWidget()
@ -235,8 +268,8 @@ void TaskViewPrivate::lock(TaskDisplay* display)
locked_display_ = display; locked_display_ = display;
} }
TaskView::TaskView(QWidget *parent) TaskView::TaskView(moveit_rviz_plugin::TaskPanel *parent, rviz::Property *root)
: QWidget(parent), d_ptr(new TaskViewPrivate(this)) : SubPanel(parent), d_ptr(new TaskViewPrivate(this))
{ {
Q_D(TaskView); Q_D(TaskView);
@ -426,23 +459,37 @@ void TaskView::onSolutionSelectionChanged(const QItemSelection &selected, const
} }
TaskSettingsPrivate::TaskSettingsPrivate(TaskSettings *q_ptr) GlobalSettingsWidgetPrivate::GlobalSettingsWidgetPrivate(GlobalSettingsWidget *q_ptr, rviz::Property *root)
: q_ptr(q_ptr) : q_ptr(q_ptr)
{ {
setupUi(q_ptr); setupUi(q_ptr);
properties = new rviz::PropertyTreeModel(root, q_ptr);
view->setModel(properties);
} }
TaskSettings::TaskSettings(QWidget *parent) GlobalSettingsWidget::GlobalSettingsWidget(moveit_rviz_plugin::TaskPanel *parent, rviz::Property *root)
: QWidget(parent), d_ptr(new TaskSettingsPrivate(this)) : SubPanel(parent), d_ptr(new GlobalSettingsWidgetPrivate(this, root))
{ {
Q_D(TaskSettings); Q_D(GlobalSettingsWidget);
connect(d->properties, &rviz::PropertyTreeModel::configChanged,
this, &GlobalSettingsWidget::configChanged);
} }
TaskSettings::~TaskSettings() GlobalSettingsWidget::~GlobalSettingsWidget()
{ {
delete d_ptr; delete d_ptr;
} }
void GlobalSettingsWidget::save(rviz::Config config)
{
d_ptr->properties->getRoot()->save(config);
}
void GlobalSettingsWidget::load(const rviz::Config &config)
{
d_ptr->properties->getRoot()->load(config);
}
} }
#include "moc_task_panel.cpp" #include "moc_task_panel.cpp"

View File

@ -42,9 +42,11 @@
#include <moveit/macros/class_forward.h> #include <moveit/macros/class_forward.h>
#include <QModelIndex> #include <QModelIndex>
class QItemSelection; class QItemSelection;
class QIcon;
namespace rviz { namespace rviz {
class WindowManagerInterface; class WindowManagerInterface;
class Property;
} }
namespace moveit_rviz_plugin { namespace moveit_rviz_plugin {
@ -53,12 +55,22 @@ class TaskSolutionVisualization;
MOVEIT_CLASS_FORWARD(TaskListModel) MOVEIT_CLASS_FORWARD(TaskListModel)
MOVEIT_CLASS_FORWARD(TaskPanel) MOVEIT_CLASS_FORWARD(TaskPanel)
/** The TaskPanel displays information about manipulation tasks in the system.
* /// Base class for all sub panels within the Task Panel
* Subscribing to task_monitoring and task_solution topics, it collects information class SubPanel : public QWidget {
* about running tasks and their solutions and allows to inspect both, Q_OBJECT
* successful solutions and failed solution attempts. public:
*/ SubPanel(QWidget* parent = nullptr) : QWidget(parent) {}
virtual void save(rviz::Config config) {}
virtual void load(const rviz::Config& config) {}
Q_SIGNALS:
void configChanged();
};
/** The TaskPanel is the central panel of this plugin, collecting various sub panels. */
class TaskPanelPrivate; class TaskPanelPrivate;
class TaskPanel: public rviz::Panel class TaskPanel: public rviz::Panel
{ {
@ -70,6 +82,9 @@ public:
TaskPanel(QWidget* parent = 0); TaskPanel(QWidget* parent = 0);
~TaskPanel(); ~TaskPanel();
/// add a new sub panel widget
void addSubPanel(SubPanel* w, const QString &title, const QIcon &icon);
/** Increment/decrement use count of singleton TaskPanel instance. /** Increment/decrement use count of singleton TaskPanel instance.
* *
* If not yet done, an instance is created. If use count drops to zero, * If not yet done, an instance is created. If use count drops to zero,
@ -88,21 +103,24 @@ protected Q_SLOTS:
class MetaTaskListModel; class MetaTaskListModel;
/** TaskView displays all known tasks.
*
* Subscribing to task_monitoring and task_solution topics, it collects information
* about running tasks and their solutions and allows to inspect both,
* successful solutions and failed solution attempts.
*/
class TaskViewPrivate; class TaskViewPrivate;
class TaskView : public QWidget { class TaskView : public SubPanel {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(TaskView) Q_DECLARE_PRIVATE(TaskView)
TaskViewPrivate *d_ptr; TaskViewPrivate *d_ptr;
public: public:
TaskView(QWidget* parent = 0); TaskView(TaskPanel* parent, rviz::Property* root);
~TaskView(); ~TaskView();
void save(rviz::Config config); void save(rviz::Config config) override;
void load(const rviz::Config& config); void load(const rviz::Config& config) override;
Q_SIGNALS:
void configChanged();
public Q_SLOTS: public Q_SLOTS:
void addTask(); void addTask();
@ -115,15 +133,18 @@ protected Q_SLOTS:
}; };
class TaskSettingsPrivate; class GlobalSettingsWidgetPrivate;
class TaskSettings : public QWidget { class GlobalSettingsWidget : public SubPanel {
Q_OBJECT Q_OBJECT
Q_DECLARE_PRIVATE(TaskSettings) Q_DECLARE_PRIVATE(GlobalSettingsWidget)
TaskSettingsPrivate *d_ptr; GlobalSettingsWidgetPrivate *d_ptr;
public: public:
TaskSettings(QWidget* parent = 0); GlobalSettingsWidget(TaskPanel* parent, rviz::Property* root);
~TaskSettings(); ~GlobalSettingsWidget();
void save(rviz::Config config) override;
void load(const rviz::Config &config) override;
}; };
} }

View File

@ -27,23 +27,9 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="tool_buttons_layout">
<item> <item>
<widget class="QToolButton" name="button_show_settings"> <spacer name="spacer">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
@ -68,6 +54,9 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QStackedWidget" name="stackedWidget"/>
</item>
</layout> </layout>
</widget> </widget>
<resources> <resources>

View File

@ -41,7 +41,7 @@
#include "task_panel.h" #include "task_panel.h"
#include "ui_task_panel.h" #include "ui_task_panel.h"
#include "ui_task_view.h" #include "ui_task_view.h"
#include "ui_task_settings.h" #include "ui_global_settings.h"
#include <rviz/panel.h> #include <rviz/panel.h>
#include <rviz/properties/property_tree_model.h> #include <rviz/properties/property_tree_model.h>
@ -58,8 +58,8 @@ public:
TaskPanelPrivate(TaskPanel *q_ptr); TaskPanelPrivate(TaskPanel *q_ptr);
TaskPanel* q_ptr; TaskPanel* q_ptr;
TaskView* tasks_widget; QButtonGroup* tool_buttons_group;
TaskSettings* settings_widget; rviz::Property* property_root;
rviz::WindowManagerInterface* window_manager_; rviz::WindowManagerInterface* window_manager_;
}; };
@ -85,11 +85,12 @@ public:
}; };
class TaskSettingsPrivate : public Ui_TaskSettings { class GlobalSettingsWidgetPrivate : public Ui_GlobalSettingsWidget {
public: public:
TaskSettingsPrivate(TaskSettings *q_ptr); GlobalSettingsWidgetPrivate(GlobalSettingsWidget *q_ptr, rviz::Property *root);
TaskSettings *q_ptr; GlobalSettingsWidget *q_ptr;
rviz::PropertyTreeModel *properties;
}; };
} }