mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#6258 General way of reordering child items in the tree view
This commit is contained in:
parent
c1bc522511
commit
1ad1f7cc05
@ -28,6 +28,8 @@ set( PROJECT_FILES
|
||||
cafPdmFieldHandle.cpp
|
||||
cafPdmFieldHandle.h
|
||||
cafPdmObjectCapability.h
|
||||
cafPdmFieldReorderCapability.cpp
|
||||
cafPdmFieldReorderCapability.h
|
||||
cafPdmObjectHandle.cpp
|
||||
cafPdmObjectHandle.h
|
||||
cafPdmPointer.cpp
|
||||
|
@ -151,8 +151,6 @@ void PdmChildArrayField<DataType*>::deleteAllChildObjectsAsync()
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Removes the pointer at index from the container. Does not delete the object pointed to.
|
||||
/// Todo: This implementation can't be necessary in the new regime. Should be to just remove
|
||||
/// the item at index (shrinking the array)
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename DataType>
|
||||
void PdmChildArrayField<DataType*>::erase( size_t index )
|
||||
|
@ -0,0 +1,143 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2020- Ceetron Solutions AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library 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.
|
||||
//
|
||||
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
#include "cafPdmFieldReorderCapability.h"
|
||||
|
||||
#include "cafAssert.h"
|
||||
|
||||
using namespace caf;
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
PdmFieldReorderCapability::PdmFieldReorderCapability( PdmPtrArrayFieldHandle* field, bool giveOwnership )
|
||||
: orderChanged( this )
|
||||
, m_field( field )
|
||||
|
||||
{
|
||||
field->addCapability( this, giveOwnership );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmFieldReorderCapability::itemCanBeMovedUp( size_t index ) const
|
||||
{
|
||||
return index != 0u;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmFieldReorderCapability::itemCanBeMovedDown( size_t index ) const
|
||||
{
|
||||
return m_field->size() > 1u && index < m_field->size() - 1u;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmFieldReorderCapability::moveItemUp( size_t index )
|
||||
{
|
||||
if ( itemCanBeMovedUp( index ) )
|
||||
{
|
||||
PdmObjectHandle* itemToShift = m_field->at( index );
|
||||
if ( itemToShift )
|
||||
{
|
||||
size_t newIndex = index - 1u;
|
||||
m_field->erase( index );
|
||||
m_field->insertAt( (int)newIndex, itemToShift );
|
||||
orderChanged.send();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmFieldReorderCapability::moveItemDown( size_t index )
|
||||
{
|
||||
if ( itemCanBeMovedDown( index ) )
|
||||
{
|
||||
PdmObjectHandle* itemToShift = m_field->at( index );
|
||||
if ( itemToShift )
|
||||
{
|
||||
size_t newIndex = index + 1u;
|
||||
m_field->erase( index );
|
||||
m_field->insertAt( (int)newIndex, itemToShift );
|
||||
orderChanged.send();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
PdmFieldReorderCapability* PdmFieldReorderCapability::addToField( PdmPtrArrayFieldHandle* field )
|
||||
{
|
||||
if ( !fieldIsReorderable( field ) )
|
||||
{
|
||||
new PdmFieldReorderCapability( field, true );
|
||||
}
|
||||
return field->capability<PdmFieldReorderCapability>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmFieldReorderCapability::fieldIsReorderable( PdmPtrArrayFieldHandle* field )
|
||||
{
|
||||
return field->capability<PdmFieldReorderCapability>() != nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void PdmFieldReorderCapability::onMoveItemUp( const SignalEmitter* emitter, size_t index )
|
||||
{
|
||||
moveItemUp( index );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void PdmFieldReorderCapability::onMoveItemDown( const SignalEmitter* emitter, size_t index )
|
||||
{
|
||||
moveItemDown( index );
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
//##################################################################################################
|
||||
//
|
||||
// Custom Visualization Core library
|
||||
// Copyright (C) 2020- Ceetron Solutions AS
|
||||
//
|
||||
// This library may be used under the terms of either the GNU General Public License or
|
||||
// the GNU Lesser General Public License as follows:
|
||||
//
|
||||
// GNU General Public License Usage
|
||||
// This library 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.
|
||||
//
|
||||
// This library 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 <<http://www.gnu.org/licenses/gpl.html>>
|
||||
// for more details.
|
||||
//
|
||||
// GNU Lesser General Public License Usage
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library 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 Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
||||
// for more details.
|
||||
//
|
||||
//##################################################################################################
|
||||
#pragma once
|
||||
|
||||
#include "cafPdmFieldCapability.h"
|
||||
#include "cafPdmPtrArrayFieldHandle.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
namespace caf
|
||||
{
|
||||
class PdmFieldReorderCapability : public PdmFieldCapability, public SignalEmitter, public SignalObserver
|
||||
{
|
||||
public:
|
||||
Signal<> orderChanged;
|
||||
|
||||
public:
|
||||
PdmFieldReorderCapability( PdmPtrArrayFieldHandle* field, bool giveOwnership );
|
||||
|
||||
bool itemCanBeMovedUp( size_t index ) const;
|
||||
bool itemCanBeMovedDown( size_t index ) const;
|
||||
|
||||
bool moveItemUp( size_t index );
|
||||
bool moveItemDown( size_t index );
|
||||
|
||||
static PdmFieldReorderCapability* addToField( PdmPtrArrayFieldHandle* field );
|
||||
static bool fieldIsReorderable( PdmPtrArrayFieldHandle* field );
|
||||
|
||||
void onMoveItemUp( const SignalEmitter* emitter, size_t index );
|
||||
void onMoveItemDown( const SignalEmitter* emitter, size_t index );
|
||||
|
||||
private:
|
||||
PdmPtrArrayFieldHandle* m_field;
|
||||
};
|
||||
|
||||
}; // namespace caf
|
@ -24,4 +24,4 @@ public:
|
||||
virtual PdmObjectHandle* at( size_t index ) = 0;
|
||||
};
|
||||
|
||||
} // namespace caf
|
||||
} // namespace caf
|
||||
|
@ -133,6 +133,26 @@ public:
|
||||
: m_emitter( emitter )
|
||||
{
|
||||
}
|
||||
|
||||
Signal( const Signal& rhs )
|
||||
: m_emitter( rhs.m_emitter )
|
||||
{
|
||||
for ( auto observerCallbackPair : rhs.m_observerCallbacks )
|
||||
{
|
||||
connect( observerCallbackPair.first, observerCallbackPair.second.first );
|
||||
}
|
||||
}
|
||||
|
||||
Signal& operator=( const Signal& rhs )
|
||||
{
|
||||
m_emitter = rhs.m_emitter;
|
||||
for ( auto observerCallbackPair : rhs.m_observerCallbacks )
|
||||
{
|
||||
connect( observerCallbackPair.first, observerCallbackPair.second.first );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~Signal()
|
||||
{
|
||||
for ( auto observerCallbackPair : m_observerCallbacks )
|
||||
@ -144,13 +164,18 @@ public:
|
||||
template <typename ClassType>
|
||||
void connect( ClassType* observer, void ( ClassType::*method )( const SignalEmitter*, Args... args ) )
|
||||
{
|
||||
static_assert( std::is_convertible<ClassType*, SignalObserver*>::value,
|
||||
"Only classes that inherit SignalObserver can connect as an observer of a Signal." );
|
||||
MemberCallback lambda = [=]( const SignalEmitter* emitter, Args... args ) {
|
||||
// Call method
|
||||
( observer->*method )( emitter, args... );
|
||||
};
|
||||
m_observerCallbacks[observer] = std::make_pair( lambda, true );
|
||||
connect( observer, lambda );
|
||||
}
|
||||
template <typename ClassType>
|
||||
void connect( ClassType* observer, const MemberCallback& callback )
|
||||
{
|
||||
static_assert( std::is_convertible<ClassType*, SignalObserver*>::value,
|
||||
"Only classes that inherit SignalObserver can connect as an observer of a Signal." );
|
||||
m_observerCallbacks[observer] = std::make_pair( callback, true );
|
||||
observer->beingDeleted.connect( this );
|
||||
}
|
||||
|
||||
@ -184,9 +209,6 @@ public:
|
||||
size_t observerCount() const { return m_observerCallbacks.size(); }
|
||||
|
||||
private:
|
||||
Signal( const Signal& rhs ) = default;
|
||||
Signal& operator=( const Signal& rhs ) = default;
|
||||
|
||||
std::map<SignalObserver*, MemberCallbackAndActiveFlag> m_observerCallbacks;
|
||||
const SignalEmitter* m_emitter;
|
||||
};
|
||||
|
@ -78,6 +78,21 @@ set( PROJECT_FILES
|
||||
cafFontTools.h
|
||||
)
|
||||
|
||||
# NOTE! Resources in this subfolder appends to the variable QRC_FILES in parent scope
|
||||
# CMakeList.txt in the application folder (parent scope) must use the following syntax
|
||||
# to make sure the QRC_FILES variable contains appended files in subfolders
|
||||
|
||||
# set( QRC_FILES
|
||||
# ${QRC_FILES}
|
||||
# Resources/MyaApplication.qrc
|
||||
# )
|
||||
|
||||
set( QRC_FILES
|
||||
${QRC_FILES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Resources/caf.qrc
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
add_library( ${PROJECT_NAME}
|
||||
${PROJECT_FILES}
|
||||
${MOC_SOURCE_FILES}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 448 B |
Binary file not shown.
After Width: | Height: | Size: 455 B |
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/caf">
|
||||
<file>Down16x16.png</file>
|
||||
<file>Up16x16.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -171,10 +171,9 @@ set( PROJECT_FILES
|
||||
)
|
||||
|
||||
add_library( ${PROJECT_NAME}
|
||||
|
||||
${PROJECT_FILES}
|
||||
|
||||
${PROJECT_FILES}
|
||||
${MOC_SOURCE_FILES}
|
||||
${QRC_FILES_CPP}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
|
@ -38,7 +38,9 @@
|
||||
|
||||
#include "cafPdmChildArrayField.h"
|
||||
#include "cafPdmField.h"
|
||||
#include "cafPdmFieldReorderCapability.h"
|
||||
#include "cafPdmObject.h"
|
||||
#include "cafPdmPtrArrayFieldHandle.h"
|
||||
#include "cafPdmUiCommandSystemProxy.h"
|
||||
#include "cafPdmUiDragDropInterface.h"
|
||||
#include "cafPdmUiEditorHandle.h"
|
||||
@ -46,9 +48,11 @@
|
||||
#include "cafPdmUiTreeViewQModel.h"
|
||||
#include "cafSelectionManager.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDragMoveEvent>
|
||||
#include <QEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QIcon>
|
||||
#include <QMenu>
|
||||
#include <QModelIndexList>
|
||||
#include <QPainter>
|
||||
@ -132,7 +136,7 @@ QWidget* PdmUiTreeViewEditor::createWidget( QWidget* parent )
|
||||
m_treeView->setModel( m_treeViewModel );
|
||||
m_treeView->installEventFilter( this );
|
||||
|
||||
m_delegate = new PdmUiTreeViewItemDelegate( m_treeView, m_treeViewModel );
|
||||
m_delegate = new PdmUiTreeViewItemDelegate( this, m_treeViewModel );
|
||||
|
||||
m_treeView->setItemDelegate( m_delegate );
|
||||
|
||||
@ -177,7 +181,7 @@ void PdmUiTreeViewEditor::configureAndUpdateUi( const QString& uiConfigName )
|
||||
|
||||
if ( m_delegate )
|
||||
{
|
||||
m_delegate->clearAttributes();
|
||||
m_delegate->clearAllTags();
|
||||
updateItemDelegateForSubTree();
|
||||
}
|
||||
}
|
||||
@ -190,6 +194,14 @@ QTreeView* PdmUiTreeViewEditor::treeView()
|
||||
return m_treeView;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
const QTreeView* PdmUiTreeViewEditor::treeView() const
|
||||
{
|
||||
return m_treeView;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -365,7 +377,7 @@ void PdmUiTreeViewEditor::selectItems( std::vector<const PdmUiItem*> uiItems )
|
||||
void PdmUiTreeViewEditor::slotOnSelectionChanged( const QItemSelection& selected, const QItemSelection& deselected )
|
||||
{
|
||||
this->updateSelectionManager();
|
||||
|
||||
this->updateItemDelegateForSubTree();
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
@ -442,15 +454,67 @@ void PdmUiTreeViewEditor::updateItemDelegateForSubTree( const QModelIndex& model
|
||||
auto allIndices = m_treeViewModel->allIndicesRecursive();
|
||||
for ( QModelIndex index : allIndices )
|
||||
{
|
||||
m_delegate->clearTags( index );
|
||||
|
||||
PdmUiItem* uiItem = m_treeViewModel->uiItemFromModelIndex( index );
|
||||
PdmUiObjectHandle* uiObjectHandle = dynamic_cast<PdmUiObjectHandle*>( uiItem );
|
||||
|
||||
if ( uiObjectHandle )
|
||||
{
|
||||
PdmObjectHandle* pdmObject = uiObjectHandle->objectHandle();
|
||||
if ( pdmObject )
|
||||
{
|
||||
PdmPtrArrayFieldHandle* arrayField = dynamic_cast<PdmPtrArrayFieldHandle*>( pdmObject->parentField() );
|
||||
if ( arrayField )
|
||||
{
|
||||
PdmFieldReorderCapability* reorderability = arrayField->capability<PdmFieldReorderCapability>();
|
||||
std::vector<PdmUiItem*> selection;
|
||||
selectedUiItems( selection );
|
||||
|
||||
if ( reorderability && index.row() >= 0 && selection.size() == 1u && selection.front() == uiItem )
|
||||
{
|
||||
size_t indexInParent = static_cast<size_t>( index.row() );
|
||||
{
|
||||
caf::PdmUiTreeViewItemAttribute::Tag tag;
|
||||
tag.icon = caf::IconProvider( ":/caf/Up16x16.png" );
|
||||
tag.selectedOnly = true;
|
||||
if ( reorderability->itemCanBeMovedUp( indexInParent ) )
|
||||
{
|
||||
tag.clicked.connect( reorderability, &PdmFieldReorderCapability::onMoveItemUp );
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.icon.setActive( false );
|
||||
}
|
||||
|
||||
m_delegate->addTag( index, tag );
|
||||
}
|
||||
{
|
||||
caf::PdmUiTreeViewItemAttribute::Tag tag;
|
||||
tag.icon = caf::IconProvider( ":/caf/Down16x16.png" );
|
||||
tag.selectedOnly = true;
|
||||
if ( reorderability->itemCanBeMovedDown( indexInParent ) )
|
||||
{
|
||||
tag.clicked.connect( reorderability, &PdmFieldReorderCapability::onMoveItemDown );
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.icon.setActive( false );
|
||||
}
|
||||
m_delegate->addTag( index, tag );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PdmUiTreeViewItemAttribute attribute;
|
||||
uiObjectHandle->objectEditorAttribute( "", &attribute );
|
||||
if ( !attribute.tag.isEmpty() )
|
||||
for ( const PdmUiTreeViewItemAttribute::Tag& tag : attribute.tags )
|
||||
{
|
||||
m_delegate->addAttribute( index, attribute );
|
||||
if ( !tag.text.isEmpty() || tag.icon.valid() )
|
||||
{
|
||||
m_delegate->addTag( index, tag );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -475,8 +539,9 @@ bool PdmUiTreeViewEditor::isAppendOfClassNameToUiItemTextEnabled()
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTreeViewQModel* model )
|
||||
: QStyledItemDelegate( parent )
|
||||
PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( PdmUiTreeViewEditor* parent, PdmUiTreeViewQModel* model )
|
||||
: QStyledItemDelegate( parent->treeView() )
|
||||
, m_treeView( parent )
|
||||
, m_model( model )
|
||||
{
|
||||
}
|
||||
@ -484,17 +549,66 @@ PdmUiTreeViewItemDelegate::PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTree
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void PdmUiTreeViewItemDelegate::clearAttributes()
|
||||
void PdmUiTreeViewItemDelegate::clearTags( QModelIndex index )
|
||||
{
|
||||
m_attributes.clear();
|
||||
m_tags.erase( index );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void PdmUiTreeViewItemDelegate::addAttribute( QModelIndex index, const PdmUiTreeViewItemAttribute& attribute )
|
||||
void PdmUiTreeViewItemDelegate::clearAllTags()
|
||||
{
|
||||
m_attributes[index] = attribute;
|
||||
m_tags.clear();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
void PdmUiTreeViewItemDelegate::addTag( QModelIndex index, const PdmUiTreeViewItemAttribute::Tag& tag )
|
||||
{
|
||||
std::vector<PdmUiTreeViewItemAttribute::Tag>& tagList = m_tags[index];
|
||||
tagList.push_back( tag );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
QRect PdmUiTreeViewItemDelegate::tagRect( const QRect& itemRect, QModelIndex index, size_t tagIndex ) const
|
||||
{
|
||||
auto it = m_tags.find( index );
|
||||
if ( it == m_tags.end() ) return QRect();
|
||||
|
||||
QSize fullSize = itemRect.size();
|
||||
|
||||
QPoint offset( 0, 0 );
|
||||
|
||||
for ( size_t i = 0; i < it->second.size(); ++i )
|
||||
{
|
||||
const PdmUiTreeViewItemAttribute::Tag& tag = it->second[i];
|
||||
if ( tag.icon.valid() )
|
||||
{
|
||||
auto icon = tag.icon.icon();
|
||||
QSize iconSize = icon->actualSize( fullSize );
|
||||
QRect iconRect;
|
||||
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
|
||||
{
|
||||
QPoint bottomRight = itemRect.bottomRight() - offset;
|
||||
QPoint topLeft = bottomRight - QPoint( iconSize.width(), iconSize.height() );
|
||||
iconRect = QRect( topLeft, bottomRight );
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint topLeft = itemRect.topLeft() + offset;
|
||||
QPoint bottomRight = topLeft + QPoint( iconSize.width(), iconSize.height() );
|
||||
iconRect = QRect( topLeft, bottomRight );
|
||||
}
|
||||
offset += QPoint( iconSize.width() + 2, 0 );
|
||||
|
||||
if ( i == tagIndex ) return iconRect;
|
||||
}
|
||||
}
|
||||
return QRect();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -504,68 +618,167 @@ void PdmUiTreeViewItemDelegate::paint( QPainter* painter, const QStyleOptionView
|
||||
{
|
||||
QStyledItemDelegate::paint( painter, option, index );
|
||||
|
||||
auto it = m_attributes.find( index );
|
||||
if ( it == m_attributes.end() ) return;
|
||||
auto it = m_tags.find( index );
|
||||
if ( it == m_tags.end() ) return;
|
||||
|
||||
// Save painter so we can restore it
|
||||
painter->save();
|
||||
|
||||
const int insideTopBottomMargins = 1;
|
||||
const int insideleftRightMargins = 6;
|
||||
const int outsideLeftRightMargins = 4;
|
||||
|
||||
QFont font = QApplication::font();
|
||||
if ( font.pixelSize() > 0 )
|
||||
{
|
||||
font.setPixelSize( std::max( 1, font.pixelSize() - 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
font.setPointSize( std::max( 1, font.pointSize() - 1 ) );
|
||||
}
|
||||
painter->setFont( font );
|
||||
|
||||
QString text = it->second.tag;
|
||||
QColor bgColor = it->second.bgColor;
|
||||
QColor fgColor = it->second.fgColor;
|
||||
|
||||
QSize textSize( QFontMetrics( font ).size( Qt::TextSingleLine, text ) );
|
||||
QRect rect = option.rect;
|
||||
QSize fullSize = rect.size();
|
||||
int textDiff = ( fullSize.height() - textSize.height() );
|
||||
|
||||
QRect textRect;
|
||||
if ( it->second.position == PdmUiTreeViewItemAttribute::AT_END )
|
||||
QPoint offset( 0, 0 );
|
||||
|
||||
for ( const PdmUiTreeViewItemAttribute::Tag& tag : it->second )
|
||||
{
|
||||
QPoint bottomRight = rect.bottomRight() - QPoint( outsideLeftRightMargins, 0 );
|
||||
QPoint textBottomRight = bottomRight - QPoint( insideleftRightMargins, textDiff / 2 );
|
||||
QPoint textTopLeft = textBottomRight - QPoint( textSize.width(), textSize.height() );
|
||||
textRect = QRect( textTopLeft, textBottomRight );
|
||||
if ( tag.selectedOnly && !( option.state & QStyle::State_Selected ) ) continue;
|
||||
|
||||
if ( tag.icon.valid() )
|
||||
{
|
||||
auto icon = tag.icon.icon();
|
||||
QSize iconSize = icon->actualSize( fullSize );
|
||||
QRect iconRect;
|
||||
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
|
||||
{
|
||||
QPoint bottomRight = rect.bottomRight() - offset;
|
||||
QPoint topLeft = bottomRight - QPoint( iconSize.width(), iconSize.height() );
|
||||
iconRect = QRect( topLeft, bottomRight );
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint topLeft = rect.topLeft() + offset;
|
||||
QPoint bottomRight = topLeft + QPoint( iconSize.width(), iconSize.height() );
|
||||
iconRect = QRect( topLeft, bottomRight );
|
||||
}
|
||||
offset += QPoint( iconSize.width() + 2, 0 );
|
||||
icon->paint( painter, iconRect );
|
||||
}
|
||||
else
|
||||
{
|
||||
const int insideTopBottomMargins = 1;
|
||||
const int insideleftRightMargins = 6;
|
||||
const int outsideLeftRightMargins = 4;
|
||||
|
||||
QFont font = QApplication::font();
|
||||
if ( font.pixelSize() > 0 )
|
||||
{
|
||||
font.setPixelSize( std::max( 1, font.pixelSize() - 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
font.setPointSize( std::max( 1, font.pointSize() - 1 ) );
|
||||
}
|
||||
painter->setFont( font );
|
||||
|
||||
QString text = tag.text;
|
||||
QColor bgColor = tag.bgColor;
|
||||
QColor fgColor = tag.fgColor;
|
||||
|
||||
QSize textSize( QFontMetrics( font ).size( Qt::TextSingleLine, text ) );
|
||||
int textDiff = ( fullSize.height() - textSize.height() );
|
||||
|
||||
QRect textRect;
|
||||
if ( tag.position == PdmUiTreeViewItemAttribute::Tag::AT_END )
|
||||
{
|
||||
QPoint bottomRight = rect.bottomRight() - QPoint( outsideLeftRightMargins, 0 ) - offset;
|
||||
QPoint textBottomRight = bottomRight - QPoint( insideleftRightMargins, textDiff / 2 );
|
||||
QPoint textTopLeft = textBottomRight - QPoint( textSize.width(), textSize.height() );
|
||||
textRect = QRect( textTopLeft, textBottomRight );
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint textTopLeft = QPoint( 0, rect.topLeft().y() ) + offset +
|
||||
QPoint( outsideLeftRightMargins + insideleftRightMargins, +textDiff / 2 );
|
||||
QPoint textBottomRight = textTopLeft + QPoint( textSize.width(), textSize.height() );
|
||||
textRect = QRect( textTopLeft, textBottomRight );
|
||||
}
|
||||
|
||||
QRect tagRect = textRect.marginsAdded(
|
||||
QMargins( insideleftRightMargins, insideTopBottomMargins, insideleftRightMargins, insideTopBottomMargins ) );
|
||||
|
||||
offset += QPoint( tagRect.width() + 2, 0 );
|
||||
|
||||
QBrush brush( bgColor );
|
||||
|
||||
painter->setBrush( brush );
|
||||
painter->setPen( bgColor );
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
const double xRoundingRadiusPercent = 50.0;
|
||||
const double yRoundingRadiusPercent = 25.0;
|
||||
painter->drawRoundedRect( tagRect, xRoundingRadiusPercent, yRoundingRadiusPercent, Qt::RelativeSize );
|
||||
|
||||
painter->setPen( fgColor );
|
||||
painter->drawText( textRect, Qt::AlignCenter, text );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QPoint textTopLeft = QPoint( 0, rect.topLeft().y() ) +
|
||||
QPoint( outsideLeftRightMargins + insideleftRightMargins, +textDiff / 2 );
|
||||
QPoint textBottomRight = textTopLeft + QPoint( textSize.width(), textSize.height() );
|
||||
textRect = QRect( textTopLeft, textBottomRight );
|
||||
}
|
||||
QRect tagRect = textRect.marginsAdded(
|
||||
QMargins( insideleftRightMargins, insideTopBottomMargins, insideleftRightMargins, insideTopBottomMargins ) );
|
||||
|
||||
QBrush brush( bgColor );
|
||||
|
||||
painter->setBrush( brush );
|
||||
painter->setPen( bgColor );
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
const double xRoundingRadiusPercent = 50.0;
|
||||
const double yRoundingRadiusPercent = 25.0;
|
||||
painter->drawRoundedRect( tagRect, xRoundingRadiusPercent, yRoundingRadiusPercent, Qt::RelativeSize );
|
||||
|
||||
painter->setPen( fgColor );
|
||||
painter->drawText( textRect, Qt::AlignCenter, text );
|
||||
|
||||
// Restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::vector<caf::PdmUiTreeViewItemAttribute::Tag> PdmUiTreeViewItemDelegate::tags( QModelIndex index ) const
|
||||
{
|
||||
auto it = m_tags.find( index );
|
||||
return it != m_tags.end() ? it->second : std::vector<caf::PdmUiTreeViewItemAttribute::Tag>();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmUiTreeViewItemDelegate::editorEvent( QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& itemIndex )
|
||||
{
|
||||
if ( event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>( event );
|
||||
|
||||
if ( mouseEvent->button() == Qt::LeftButton && mouseEvent->modifiers() == Qt::NoModifier )
|
||||
{
|
||||
PdmUiTreeViewItemAttribute::Tag tag;
|
||||
if ( tagClicked( mouseEvent->pos(), option.rect, itemIndex, &tag ) )
|
||||
{
|
||||
QModelIndex parentIndex = itemIndex.parent();
|
||||
|
||||
auto uiItem = m_treeView->uiItemFromModelIndex( itemIndex );
|
||||
auto parentUiItem = m_treeView->uiItemFromModelIndex( parentIndex );
|
||||
|
||||
tag.clicked.send( (size_t)itemIndex.row() );
|
||||
|
||||
m_treeView->updateSubTree( parentUiItem );
|
||||
m_treeView->selectAsCurrentItem( uiItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent( event, model, option, itemIndex );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool PdmUiTreeViewItemDelegate::tagClicked( const QPoint& pos,
|
||||
const QRect& itemRect,
|
||||
const QModelIndex& itemIndex,
|
||||
PdmUiTreeViewItemAttribute::Tag* tag ) const
|
||||
{
|
||||
if ( itemIndex.isValid() )
|
||||
{
|
||||
auto itemTags = tags( itemIndex );
|
||||
|
||||
for ( size_t i = 0; i < itemTags.size(); ++i )
|
||||
{
|
||||
QRect rect = tagRect( itemRect, itemIndex, i );
|
||||
if ( rect.contains( pos ) )
|
||||
{
|
||||
*tag = itemTags[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // end namespace caf
|
||||
|
@ -36,9 +36,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cafIconProvider.h"
|
||||
#include "cafPdmUiFieldEditorHandle.h"
|
||||
#include "cafPdmUiTreeEditorHandle.h"
|
||||
#include "cafPdmUiTreeViewQModel.h"
|
||||
#include "cafSignal.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QColor>
|
||||
@ -48,6 +50,8 @@
|
||||
#include <QTreeView>
|
||||
#include <QWidget>
|
||||
|
||||
#include <functional>
|
||||
|
||||
class MySortFilterProxyModel;
|
||||
|
||||
class QGridLayout;
|
||||
@ -67,35 +71,60 @@ class PdmUiTreeViewWidget;
|
||||
class PdmUiTreeViewItemAttribute : public PdmUiEditorAttribute
|
||||
{
|
||||
public:
|
||||
enum Position
|
||||
struct Tag : public SignalEmitter
|
||||
{
|
||||
IN_FRONT,
|
||||
AT_END
|
||||
enum Position
|
||||
{
|
||||
IN_FRONT,
|
||||
AT_END
|
||||
};
|
||||
Tag()
|
||||
: text()
|
||||
, position( AT_END )
|
||||
, bgColor( Qt::red )
|
||||
, fgColor( Qt::white )
|
||||
, selectedOnly( false )
|
||||
, clicked( this )
|
||||
{
|
||||
}
|
||||
QString text;
|
||||
IconProvider icon;
|
||||
Position position;
|
||||
QColor bgColor;
|
||||
QColor fgColor;
|
||||
bool selectedOnly;
|
||||
|
||||
caf::Signal<size_t> clicked;
|
||||
};
|
||||
PdmUiTreeViewItemAttribute()
|
||||
: tag()
|
||||
, position( AT_END )
|
||||
, bgColor( Qt::red )
|
||||
, fgColor( Qt::white )
|
||||
{
|
||||
}
|
||||
QString tag;
|
||||
Position position;
|
||||
QColor bgColor;
|
||||
QColor fgColor;
|
||||
|
||||
std::vector<Tag> tags;
|
||||
};
|
||||
|
||||
class PdmUiTreeViewItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
PdmUiTreeViewItemDelegate( QObject* parent, PdmUiTreeViewQModel* model );
|
||||
void clearAttributes();
|
||||
void addAttribute( QModelIndex index, const PdmUiTreeViewItemAttribute& attribute );
|
||||
PdmUiTreeViewItemDelegate( PdmUiTreeViewEditor* parent, PdmUiTreeViewQModel* model );
|
||||
void clearTags( QModelIndex index );
|
||||
void clearAllTags();
|
||||
void addTag( QModelIndex index, const PdmUiTreeViewItemAttribute::Tag& tag );
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
|
||||
std::vector<PdmUiTreeViewItemAttribute::Tag> tags( QModelIndex index ) const;
|
||||
|
||||
protected:
|
||||
bool editorEvent( QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& itemIndex ) override;
|
||||
bool tagClicked( const QPoint& clickPos,
|
||||
const QRect& itemRect,
|
||||
const QModelIndex& itemIndex,
|
||||
PdmUiTreeViewItemAttribute::Tag* tag ) const;
|
||||
QRect tagRect( const QRect& itemRect, QModelIndex itemIndex, size_t tagIndex ) const;
|
||||
|
||||
private:
|
||||
PdmUiTreeViewQModel* m_model;
|
||||
std::map<QModelIndex, PdmUiTreeViewItemAttribute> m_attributes;
|
||||
PdmUiTreeViewEditor* m_treeView;
|
||||
PdmUiTreeViewQModel* m_model;
|
||||
std::map<QModelIndex, std::vector<PdmUiTreeViewItemAttribute::Tag>> m_tags;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@ -129,8 +158,9 @@ public:
|
||||
void enableAppendOfClassNameToUiItemText( bool enable );
|
||||
bool isAppendOfClassNameToUiItemTextEnabled();
|
||||
|
||||
QTreeView* treeView();
|
||||
bool isTreeItemEditWidgetActive() const;
|
||||
QTreeView* treeView();
|
||||
const QTreeView* treeView() const;
|
||||
bool isTreeItemEditWidgetActive() const;
|
||||
|
||||
void selectAsCurrentItem( const PdmUiItem* uiItem );
|
||||
void selectItems( std::vector<const PdmUiItem*> uiItems );
|
||||
@ -151,7 +181,6 @@ protected:
|
||||
void configureAndUpdateUi( const QString& uiConfigName ) override;
|
||||
|
||||
void updateMySubTree( PdmUiItem* uiItem ) override;
|
||||
|
||||
void updateContextMenuSignals();
|
||||
|
||||
private slots:
|
||||
|
Loading…
Reference in New Issue
Block a user