rework RViz panel

There's no need for individually resizable columns, but all numeric
content should autoresize and be visible all the time.

We will add an option to hide the time column in the future.

Remove intermediate AutoAdjustingTreeView layer to simplify code.
Resizing the columns did not work perfectly well before
and the auto_hide_cols_ feature was not really used.
This commit is contained in:
v4hn 2020-03-19 21:11:44 +01:00
parent 25fea7198a
commit 75bc6566f6
4 changed files with 125 additions and 138 deletions

View File

@ -2,6 +2,7 @@
* Software License Agreement (BSD License)
*
* Copyright (c) 2017, Bielefeld University
* Copyright (c) 2020, Hamburg University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -359,99 +360,7 @@ Qt::DropActions TaskListModel::supportedDropActions() const {
return Qt::CopyAction | Qt::MoveAction;
}
AutoAdjustingTreeView::AutoAdjustingTreeView(QWidget* parent) : QTreeView(parent) {
// consider viewportSizeHint()
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
#endif
}
void AutoAdjustingTreeView::setStretchSection(int section) {
stretch_section_ = section;
updateGeometry();
}
void AutoAdjustingTreeView::setAutoHideSections(const QList<int>& sections) {
auto_hide_cols_ = sections;
updateGeometry();
}
void AutoAdjustingTreeView::setModel(QAbstractItemModel* model) {
size_hints_.clear();
QTreeView::setModel(model);
updateGeometry();
}
QSize AutoAdjustingTreeView::viewportSizeHint() const {
bool preferred = sizePolicy().horizontalPolicy() & QSizePolicy::ShrinkFlag;
auto m = model();
auto* h = header();
size_hints_.clear();
int width = 0;
for (int i = 0, end = m ? m->columnCount() : 0; i < end; ++i) {
size_hints_.push_back(h->sectionSizeHint(i));
if (preferred || !auto_hide_cols_.contains(i))
width += size_hints_.back();
}
QSize main_size(width, sizeHintForRow(0) * ((!preferred || !m) ? 2 : m->rowCount()));
// add size for header
QSize header_size(0, header()->isVisible() ? header()->height() : 0);
// add size for scrollbars
QSize scrollbars(verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0,
horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0);
return main_size + header_size + scrollbars;
}
void AutoAdjustingTreeView::resizeEvent(QResizeEvent* event) {
auto* m = model();
int columns = m ? m->columnCount() : 0;
if ((int)size_hints_.size() != columns)
viewportSizeHint();
// auto hide/show columns > 0, stretch last column to width
int available_width = event->size().width();
int required_width = std::accumulate(size_hints_.begin(), size_hints_.end(), 0);
std::vector<int> width = size_hints_;
// if required is larger than available width, try to hide some columns
QListIterator<int> it(auto_hide_cols_);
for (it.toBack(); it.hasPrevious() && required_width > available_width;) {
int section = it.previous();
required_width -= size_hints_[section];
width[section] = 0;
}
// extend width to current column width if possible
for (int i = 0; i < columns; ++i) {
if (i == stretch_section_)
continue; // ignore auto-stretch section for now
int delta = columnWidth(i) > 0 ? columnWidth(i) - width[i] : 0;
if (delta < 0 || required_width + delta <= available_width) {
width[i] += delta;
required_width += delta;
}
}
// stretch section if there is still space available
if (stretch_section_ >= 0 && stretch_section_ < (int)width.size() && width[stretch_section_] > 0 &&
available_width > required_width)
width[stretch_section_] += available_width - required_width;
// apply stuff
for (int i = 0; i < columns; ++i)
setColumnWidth(i, width[i]);
}
TaskListView::TaskListView(QWidget* parent) : AutoAdjustingTreeView(parent) {
setStretchSection(0);
}
TaskListView::TaskListView(QWidget* parent) : QTreeView(parent) {}
// dropping onto an item, should expand this item
void TaskListView::dropEvent(QDropEvent* event) {
@ -460,6 +369,64 @@ void TaskListView::dropEvent(QDropEvent* event) {
if (event->isAccepted())
expand(index);
}
void TaskListView::setModel(QAbstractItemModel* model) {
QTreeView::setModel(model);
if (header()->count() >= 4) {
header()->setSectionResizeMode(0, QHeaderView::Stretch);
updateColumnWidth();
}
}
void TaskListView::dataChanged(const QModelIndex& /*topLeft*/, const QModelIndex& bottomRight,
const QVector<int>& /*roles*/) {
if (bottomRight.column() > 0) {
updateColumnWidth();
}
}
void TaskListView::updateColumnWidth() {
for (int i = 3; i > 0; --i) {
header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
}
SolutionListView::SolutionListView(QWidget* parent) : QTreeView(parent) {}
void SolutionListView::setModel(QAbstractItemModel* model) {
QTreeView::setModel(model);
updateColumnWidth();
}
void SolutionListView::dataChanged(const QModelIndex& /*topLeft*/, const QModelIndex& bottomRight,
const QVector<int>& /*roles*/) {
if (bottomRight.column() > 0) {
updateColumnWidth();
}
}
void SolutionListView::resizeEvent(QResizeEvent* e) {
QTreeView::resizeEvent(e);
updateColumnWidth();
}
void SolutionListView::updateColumnWidth() {
// do nothing if current model is not what we expect
if (header()->count() < 3) {
return;
}
for (int i = 0; i < 2; ++i) {
header()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
}
const int stretch_size = viewport()->size().width() - header()->sectionPosition(2);
const int content_size = sizeHintForColumn(2);
header()->resizeSection(2, std::max(stretch_size, content_size));
}
} // namespace moveit_rviz_plugin
#include "moc_task_list_model.cpp"

View File

@ -2,6 +2,7 @@
* Software License Agreement (BSD License)
*
* Copyright (c) 2017, Bielefeld University
* Copyright (c) 2020, Hamburg University
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,6 +48,7 @@
#include <QAbstractItemModel>
#include <QTreeView>
#include <QTableView>
#include <memory>
#include <QPointer>
@ -178,34 +180,34 @@ protected Q_SLOTS:
void highlightStage(size_t id);
};
class AutoAdjustingTreeView : public QTreeView
{
Q_OBJECT
Q_PROPERTY(int stretchSection READ stretchSection WRITE setStretchSection)
mutable std::vector<int> size_hints_; // size hints for sections
QList<int> auto_hide_cols_; // auto-hiding sections
int stretch_section_ = -1;
public:
AutoAdjustingTreeView(QWidget* parent = nullptr);
int stretchSection() const { return stretch_section_; }
void setStretchSection(int section);
void setAutoHideSections(const QList<int>& sections);
void setModel(QAbstractItemModel* model) override;
QSize viewportSizeHint() const override;
void resizeEvent(QResizeEvent* event) override;
};
class TaskListView : public AutoAdjustingTreeView
class TaskListView : public QTreeView
{
Q_OBJECT
public:
TaskListView(QWidget* parent = nullptr);
void dropEvent(QDropEvent* event) override;
void setModel(QAbstractItemModel* model) override;
void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
const QVector<int>& roles = QVector<int>()) override;
protected:
void updateColumnWidth();
};
class SolutionListView : public QTreeView
{
Q_OBJECT
public:
SolutionListView(QWidget* parent = nullptr);
void setModel(QAbstractItemModel* model) override;
void dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight,
const QVector<int>& roles = QVector<int>()) override;
void resizeEvent(QResizeEvent* event) override;
protected:
void updateColumnWidth();
};
} // namespace moveit_rviz_plugin

View File

@ -234,9 +234,6 @@ TaskViewPrivate::TaskViewPrivate(TaskView* q_ptr) : q_ptr(q_ptr), exec_action_cl
tasks_view->setDropIndicatorShown(true);
tasks_view->setDragEnabled(true);
solutions_view->setAutoHideSections({ 1, 2 });
solutions_view->setStretchSection(2);
// init actions
tasks_view->addActions({ actionAddLocalTask, actionRemoveTaskTreeRows });
}
@ -304,15 +301,15 @@ void TaskView::save(rviz::Config config) {
write_splitter_sizes(d_ptr->tasks_property_splitter, "property_splitter");
write_splitter_sizes(d_ptr->tasks_solutions_splitter, "solutions_splitter");
auto write_column_sizes = [&config](QTreeView* view, const QString& key) {
auto write_column_sizes = [&config](QHeaderView* view, const QString& key) {
rviz::Config group = config.mapMakeChild(key);
for (int c = 0, end = view->header()->count(); c != end; ++c) {
for (int c = 0, end = view->count(); c != end; ++c) {
rviz::Config item = group.listAppendNew();
item.setValue(view->columnWidth(c));
item.setValue(view->sectionSize(c));
}
};
write_column_sizes(d_ptr->tasks_view, "tasks_view_columns");
write_column_sizes(d_ptr->solutions_view, "solutions_view_columns");
write_column_sizes(d_ptr->tasks_view->header(), "tasks_view_columns");
write_column_sizes(d_ptr->solutions_view->header(), "solutions_view_columns");
const QHeaderView* view = d_ptr->solutions_view->header();
rviz::Config group = config.mapMakeChild("solution_sorting");
@ -413,10 +410,10 @@ void TaskView::onCurrentStageChanged(const QModelIndex& current, const QModelInd
}
// update the PropertyModel
view = d_ptr->property_view;
sm = view->selectionModel();
QTreeView* pview = d_ptr->property_view;
sm = pview->selectionModel();
m = task ? task->getPropertyModel(task_index) : nullptr;
view->setModel(m);
pview->setModel(m);
delete sm; // we don't store the selection model
}

View File

@ -31,7 +31,7 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout1">
<property name="spacing">
<number>0</number>
@ -64,11 +64,23 @@
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="indentation">
<number>15</number>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
<widget class="moveit_rviz_plugin::AutoAdjustingTreeView" name="solutions_view">
<widget class="moveit_rviz_plugin::SolutionListView" name="solutions_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>1</horstretch>
@ -78,6 +90,15 @@
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
@ -87,15 +108,15 @@
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout2">
<property name="spacing">
<number>0</number>
@ -141,16 +162,16 @@
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
<customwidget>
<class>moveit_rviz_plugin::AutoAdjustingTreeView</class>
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
<customwidget>
<class>rviz::PropertyTreeWidget</class>
<extends>QTreeView</extends>
<header location="global">rviz/properties/property_tree_widget.h</header>
</customwidget>
<customwidget>
<class>moveit_rviz_plugin::SolutionListView</class>
<extends>QTreeView</extends>
<header>task_list_model.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>