From 526e1cafbcfe6693372203c0b91a7a2b8a7bf670 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Wed, 13 Sep 2017 11:24:29 +0200 Subject: [PATCH] #1852 Curve Creator : Add custom object editor --- .../UserInterface/CMakeLists_files.cmake | 3 + .../UserInterface/RiuCustomObjectEditor.cpp | 263 ++++++++++++++++++ .../UserInterface/RiuCustomObjectEditor.h | 82 ++++++ 3 files changed, 348 insertions(+) create mode 100644 ApplicationCode/UserInterface/RiuCustomObjectEditor.cpp create mode 100644 ApplicationCode/UserInterface/RiuCustomObjectEditor.h diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index b74b3e449f..7076c4321d 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -50,6 +50,7 @@ ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.h ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.h ${CEE_CURRENT_LIST_DIR}RiuPlotObjectPicker.h ${CEE_CURRENT_LIST_DIR}RiuContextMenuLauncher.h +${CEE_CURRENT_LIST_DIR}RiuCustomObjectEditor.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -97,6 +98,7 @@ ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.cpp ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.cpp ${CEE_CURRENT_LIST_DIR}RiuPlotObjectPicker.cpp ${CEE_CURRENT_LIST_DIR}RiuContextMenuLauncher.cpp +${CEE_CURRENT_LIST_DIR}RiuCustomObjectEditor.cpp ) list(APPEND CODE_HEADER_FILES @@ -130,6 +132,7 @@ ${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.h ${CEE_CURRENT_LIST_DIR}RiuFlowCharacteristicsPlot.h ${CEE_CURRENT_LIST_DIR}RiuNightchartsWidget.h ${CEE_CURRENT_LIST_DIR}RiuMessagePanel.h +${CEE_CURRENT_LIST_DIR}RiuCustomObjectEditor.h ) list(APPEND QT_UI_FILES diff --git a/ApplicationCode/UserInterface/RiuCustomObjectEditor.cpp b/ApplicationCode/UserInterface/RiuCustomObjectEditor.cpp new file mode 100644 index 0000000000..09ef5dfd75 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuCustomObjectEditor.cpp @@ -0,0 +1,263 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuCustomObjectEditor.h" + +#include "cafPdmUiGroup.h" + +#include "QMinimizePanel.h" + +#include +#include + + +//================================================================================================== +/// +//================================================================================================== +class WidgetCellIds +{ +public: + WidgetCellIds(QWidget* w, const std::vector& occupiedCellIds) + : m_customWidget(w), + m_customWidgetCellIds(occupiedCellIds) + { + } + + QWidget* m_customWidget; + std::vector m_customWidgetCellIds; +}; + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCustomObjectEditor::RiuCustomObjectEditor() +{ + m_columnCount = 3; + m_rowCount = 2; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCustomObjectEditor::~RiuCustomObjectEditor() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::defineGridLayout(int rowCount, int columnCount) +{ + m_rowCount = rowCount; + m_columnCount = columnCount; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::addWidget(QWidget* widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment /*= 0*/) +{ + CAF_ASSERT(isAreaAvailable(row, column, rowSpan, columnSpan)); + + m_customWidgetAreas.push_back(WidgetCellIds(widget, RiuCustomObjectEditor::cellIds(row, column, rowSpan, columnSpan))); + + // The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it. + m_layout->addWidget(widget, row, column, rowSpan, columnSpan, alignment); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::removeWidget(QWidget* widget) +{ + size_t indexToRemove = size_t(-1); + for (size_t i = 0; i < m_customWidgetAreas.size(); i++) + { + if (widget == m_customWidgetAreas[i].m_customWidget) + { + indexToRemove = i; + break; + } + } + + if (indexToRemove != size_t(-1)) + { + m_layout->removeWidget(widget); + + m_customWidgetAreas.erase(m_customWidgetAreas.begin() + indexToRemove); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::addBlankCell(int row, int column) +{ + m_customWidgetAreas.push_back(WidgetCellIds(nullptr, RiuCustomObjectEditor::cellIds(row, column, 1, 1))); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RiuCustomObjectEditor::createWidget(QWidget* parent) +{ + QWidget* widget = new QWidget(parent); + + m_layout = new QGridLayout(); + m_layout->setContentsMargins(0, 0, 0, 0); + widget->setLayout(m_layout); + + return widget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector& topLevelUiItems, const QString& uiConfigName) +{ + resetCellId(); + + QWidget* previousTabOrderWidget = NULL; + + for (size_t i = 0; i < topLevelUiItems.size(); ++i) + { + if (topLevelUiItems[i]->isUiHidden(uiConfigName)) continue; + + if (topLevelUiItems[i]->isUiGroup()) + { + caf::PdmUiGroup* group = static_cast(topLevelUiItems[i]); + QMinimizePanel* groupBox = findOrCreateGroupBox(this->widget(), group, uiConfigName); + + /// Insert the group box at the correct position of the parent layout + int nextCellId = getNextAvailableCellId(); + std::pair rowCol = rowAndColumn(nextCellId); + m_layout->addWidget(groupBox, rowCol.first, rowCol.second, 1, 1); + + const std::vector& groupChildren = group->uiItems(); + recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn(groupChildren, groupBox->contentFrame(), uiConfigName); + } + + // NB! Only groups at top level are handled, fields at top level are not added to layout + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuCustomObjectEditor::isAreaAvailable(int row, int column, int rowSpan, int columnSpan) const +{ + auto candidateCells = RiuCustomObjectEditor::cellIds(row, column, rowSpan, columnSpan); + for (auto candidateCell : candidateCells) + { + if (!isCellIdAvailable(candidateCell)) + { + return false; + } + } + + if (row + rowSpan > m_rowCount) return false; + if (column + columnSpan > m_columnCount) return false; + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuCustomObjectEditor::isCellIdAvailable(int cellId) const +{ + for (auto customArea : m_customWidgetAreas) + { + for (auto occupiedCell : customArea.m_customWidgetCellIds) + { + if (cellId == occupiedCell) + { + return false; + } + } + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCustomObjectEditor::resetCellId() +{ + m_currentCellId = 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RiuCustomObjectEditor::rowAndColumn(int cellId) const +{ + int column = cellId % m_columnCount; + int row = cellId / m_columnCount; + + return std::make_pair(row, column); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuCustomObjectEditor::cellId(int row, int column) const +{ + return row * m_columnCount + column; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuCustomObjectEditor::getNextAvailableCellId() +{ + while (!isCellIdAvailable(m_currentCellId) && m_currentCellId < (m_rowCount * m_columnCount)) + { + m_currentCellId++; + } + + if (!isCellIdAvailable(m_currentCellId)) + { + return -1; + } + else + { + return m_currentCellId++; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiuCustomObjectEditor::cellIds(int row, int column, int rowSpan, int columnSpan) const +{ + std::vector cells; + + for (auto r = row; r < row + rowSpan; r++) + { + for (auto c = column; c < column + columnSpan; c++) + { + cells.push_back(cellId(r, c)); + } + } + + return cells; +} diff --git a/ApplicationCode/UserInterface/RiuCustomObjectEditor.h b/ApplicationCode/UserInterface/RiuCustomObjectEditor.h new file mode 100644 index 0000000000..bc3d7e0578 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuCustomObjectEditor.h @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmUiWidgetBasedObjectEditor.h" + +#include + +#include + +class QGridLayout; +class QString; +class QWidget; + +class WidgetCellIds; + +namespace caf +{ + +class PdmUiItem; +class PdmUiGroup; +}; + +//================================================================================================== +/// Automatically layout top level groups into a grid layout +/// +/// User defined external widgets can be inserted into grid layout cells, and these cells +/// are excluded for automatic layout +//================================================================================================== +class RiuCustomObjectEditor : public caf::PdmUiWidgetBasedObjectEditor +{ + Q_OBJECT +public: + RiuCustomObjectEditor(); + ~RiuCustomObjectEditor(); + + void defineGridLayout(int rowCount, int columnCount); + + // See QGridLayout::addWidget + void addWidget(QWidget* widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0); + void removeWidget(QWidget* widget); + + void addBlankCell(int row, int column); + +private: + virtual QWidget* createWidget(QWidget* parent) override; + virtual void recursivelyConfigureAndUpdateTopLevelUiItems(const std::vector& topLevelUiItems, + const QString& uiConfigName) override; + + bool isAreaAvailable(int row, int column, int rowSpan, int columnSpan) const; + bool isCellIdAvailable(int cellId) const; + void resetCellId(); + int getNextAvailableCellId(); + int cellId(int row, int column) const; + std::pair rowAndColumn(int cellId) const; + std::vector cellIds(int row, int column, int rowSpan, int columnSpan) const; + +private: + QPointer m_layout; + + int m_rowCount; + int m_columnCount; + int m_currentCellId; + + std::vector m_customWidgetAreas; +};