From 75bc6566f6474ab7fcb158f6789ac6e31e71aa73 Mon Sep 17 00:00:00 2001 From: v4hn Date: Thu, 19 Mar 2020 21:11:44 +0100 Subject: [PATCH] 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. --- .../src/task_list_model.cpp | 153 +++++++----------- .../src/task_list_model.h | 48 +++--- .../motion_planning_tasks/src/task_panel.cpp | 19 +-- .../motion_planning_tasks/src/task_view.ui | 43 +++-- 4 files changed, 125 insertions(+), 138 deletions(-) diff --git a/visualization/motion_planning_tasks/src/task_list_model.cpp b/visualization/motion_planning_tasks/src/task_list_model.cpp index 26dcdf83..e04b0b92 100644 --- a/visualization/motion_planning_tasks/src/task_list_model.cpp +++ b/visualization/motion_planning_tasks/src/task_list_model.cpp @@ -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& 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 width = size_hints_; - - // if required is larger than available width, try to hide some columns - QListIterator 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& /*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& /*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" diff --git a/visualization/motion_planning_tasks/src/task_list_model.h b/visualization/motion_planning_tasks/src/task_list_model.h index 13a31b5b..fd27c159 100644 --- a/visualization/motion_planning_tasks/src/task_list_model.h +++ b/visualization/motion_planning_tasks/src/task_list_model.h @@ -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 #include +#include #include #include @@ -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 size_hints_; // size hints for sections - QList 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& 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& roles = QVector()) 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& roles = QVector()) override; + void resizeEvent(QResizeEvent* event) override; + +protected: + void updateColumnWidth(); }; } // namespace moveit_rviz_plugin diff --git a/visualization/motion_planning_tasks/src/task_panel.cpp b/visualization/motion_planning_tasks/src/task_panel.cpp index 797d69f8..fee4cad9 100644 --- a/visualization/motion_planning_tasks/src/task_panel.cpp +++ b/visualization/motion_planning_tasks/src/task_panel.cpp @@ -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 } diff --git a/visualization/motion_planning_tasks/src/task_view.ui b/visualization/motion_planning_tasks/src/task_view.ui index 8ae8aa59..bdda7ec6 100644 --- a/visualization/motion_planning_tasks/src/task_view.ui +++ b/visualization/motion_planning_tasks/src/task_view.ui @@ -31,7 +31,7 @@ Qt::Vertical - + 0 @@ -64,11 +64,23 @@ Qt::ActionsContextMenu + + 15 + + + true + + + true + + + true + false - + 1 @@ -78,6 +90,15 @@ QAbstractItemView::ExtendedSelection + + QAbstractItemView::SelectRows + + + Qt::ElideNone + + + QAbstractItemView::ScrollPerPixel + false @@ -87,15 +108,15 @@ true - - false - + + true + - + 0 @@ -141,16 +162,16 @@ QTreeView
task_list_model.h
- - moveit_rviz_plugin::AutoAdjustingTreeView - QTreeView -
task_list_model.h
-
rviz::PropertyTreeWidget QTreeView
rviz/properties/property_tree_widget.h
+ + moveit_rviz_plugin::SolutionListView + QTreeView +
task_list_model.h
+