diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt index 220e7d25b4..5bc529e535 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt @@ -47,6 +47,10 @@ set(PROJECT_FILES cafUiTreeItem.h cafPdmUiGroup.cpp cafPdmUiGroup.h + cafPdmUiLabel.cpp + cafPdmUiLabel.h + cafPdmUiButton.cpp + cafPdmUiButton.h cafSelectionManager.cpp cafSelectionManager.h cafSelectionChangedReceiver.h diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.cpp new file mode 100644 index 0000000000..dea2f17ab5 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.cpp @@ -0,0 +1,116 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2017 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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUiButton.h" + +namespace caf +{ + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiButton::PdmUiButton() + : m_alignment( Qt::AlignLeft | Qt::AlignTop ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiButton::PdmUiButton( const QString& buttonText, const ClickCallback& callback ) + : m_alignment( Qt::AlignLeft | Qt::AlignTop ) + , m_clickCallback( callback ) +{ + setUiName( buttonText ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiButton::setIcon( const IconProvider& iconProvider ) +{ + setUiIcon( iconProvider ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiButton::setIconFromResourceString( const QString& iconResourceName ) +{ + setUiIconFromResourceString( iconResourceName ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiButton::setAlignment( Qt::Alignment alignment ) +{ + m_alignment = alignment; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Qt::Alignment PdmUiButton::alignment() const +{ + return m_alignment; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiButton::setClickCallback( const ClickCallback& callback ) +{ + m_clickCallback = callback; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiButton::ClickCallback PdmUiButton::clickCallback() const +{ + return m_clickCallback; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiButton::isUiGroup() const +{ + return false; +} + +} // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.h new file mode 100644 index 0000000000..298dbc9e82 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiButton.h @@ -0,0 +1,73 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2017 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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cafPdmUiItem.h" + +#include + +namespace caf +{ +//================================================================================================== +/// Class representing a button to be displayed in the GUI without connection to a PDM field +//================================================================================================== + +class PdmUiButton : public PdmUiItem +{ +public: + using ClickCallback = std::function; + + PdmUiButton(); + PdmUiButton( const QString& buttonText, const ClickCallback& callback ); + + void setIcon( const IconProvider& iconProvider ); + void setIconFromResourceString( const QString& iconResourceName ); + + void setAlignment( Qt::Alignment alignment ); + Qt::Alignment alignment() const; + + void setClickCallback( const ClickCallback& callback ); + ClickCallback clickCallback() const; + + bool isUiGroup() const override; + +private: + Qt::Alignment m_alignment; + ClickCallback m_clickCallback; +}; + +} // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.cpp new file mode 100644 index 0000000000..352a12e91a --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.cpp @@ -0,0 +1,65 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2017 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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUiLabel.h" + +namespace caf +{ + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiLabel::PdmUiLabel() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiLabel::PdmUiLabel( const QString& labelText ) +{ + setUiName( labelText ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiLabel::isUiGroup() const +{ + return false; +} + +} // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.h new file mode 100644 index 0000000000..2969ef1522 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiLabel.h @@ -0,0 +1,56 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2017 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 <> +// 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 <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cafPdmUiItem.h" + +namespace caf +{ +//================================================================================================== +/// Class representing a label to be displayed in the GUI without connection to a PDM field +//================================================================================================== + +class PdmUiLabel : public PdmUiItem +{ +public: + PdmUiLabel(); + explicit PdmUiLabel( const QString& labelText ); + + bool isUiGroup() const override; +}; + +} // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp index eacaf1bd3e..4e90625616 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp @@ -37,7 +37,9 @@ #include "cafPdmUiOrdering.h" #include "cafPdmObjectHandle.h" +#include "cafPdmUiButton.h" #include "cafPdmUiFieldHandle.h" +#include "cafPdmUiLabel.h" #include "cafPdmUiObjectHandle.h" namespace caf @@ -47,11 +49,14 @@ namespace caf //-------------------------------------------------------------------------------------------------- PdmUiOrdering::~PdmUiOrdering() { - for ( auto& createdGroup : m_createdGroups ) - { - delete createdGroup; - createdGroup = nullptr; - } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiOrdering::PdmUiOrdering() + : m_skipRemainingFields( false ) +{ } //-------------------------------------------------------------------------------------------------- @@ -59,13 +64,40 @@ PdmUiOrdering::~PdmUiOrdering() //-------------------------------------------------------------------------------------------------- PdmUiGroup* PdmUiOrdering::addNewGroup( const QString& displayName, LayoutOptions layout ) { - auto* group = new PdmUiGroup; + auto group = std::make_unique(); group->setUiName( displayName ); - m_createdGroups.push_back( group ); - m_ordering.emplace_back( group, layout ); + m_ordering.emplace_back( group.get(), layout ); + m_createdGroups.push_back( std::move( group ) ); - return group; + return m_createdGroups.back().get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiLabel* PdmUiOrdering::addNewLabel( const QString& labelText, LayoutOptions layout ) +{ + auto label = std::make_unique( labelText ); + + m_ordering.emplace_back( label.get(), layout ); + m_createdLabels.push_back( std::move( label ) ); + + return m_createdLabels.back().get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiButton* + PdmUiOrdering::addNewButton( const QString& buttonText, const std::function& callback, LayoutOptions layout ) +{ + auto button = std::make_unique( buttonText, callback ); + + m_ordering.emplace_back( button.get(), layout ); + m_createdButtons.push_back( std::move( button ) ); + + return m_createdButtons.back().get(); } //-------------------------------------------------------------------------------------------------- @@ -179,16 +211,14 @@ caf::PdmUiGroup* PdmUiOrdering::insertNewGroupWithKeyword( size_t index, const QString& groupKeyword, LayoutOptions layout ) { - auto* group = new PdmUiGroup; + auto group = std::make_unique(); group->setUiName( displayName ); - - m_createdGroups.push_back( group ); - - m_ordering.insert( m_ordering.begin() + index, std::make_pair( group, layout ) ); - group->setKeyword( groupKeyword ); - return group; + m_ordering.insert( m_ordering.begin() + index, std::make_pair( group.get(), layout ) ); + m_createdGroups.push_back( std::move( group ) ); + + return m_createdGroups.back().get(); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h index f9fc0b788c..34bba0e898 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h @@ -39,11 +39,16 @@ #include "cafPdmUiItem.h" #include + +#include +#include #include namespace caf { class PdmUiGroup; +class PdmUiLabel; +class PdmUiButton; class PdmFieldHandle; class PdmObjectHandle; @@ -71,8 +76,7 @@ public: using RowLayout = std::vector; using TableLayout = std::vector; - PdmUiOrdering() - : m_skipRemainingFields( false ) {}; + PdmUiOrdering(); virtual ~PdmUiOrdering(); PdmUiOrdering( const PdmUiOrdering& ) = delete; @@ -91,10 +95,16 @@ public: const PdmFieldHandle* fieldToInsert, LayoutOptions layout = defaultLayoutOptions() ); - PdmUiGroup* addNewGroup( const QString& displayName, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiGroup* addNewGroup( const QString& displayName, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiLabel* addNewLabel( const QString& labelText, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiButton* addNewButton( const QString& buttonText, + const std::function& callback, + LayoutOptions layout = defaultLayoutOptions() ); + PdmUiGroup* createGroupBeforeGroup( const QString& groupId, const QString& displayName, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiGroup* createGroupBeforeItem( const PdmUiItem* item, const QString& displayName, LayoutOptions layout = defaultLayoutOptions() ); @@ -102,10 +112,12 @@ public: PdmUiGroup* addNewGroupWithKeyword( const QString& displayName, const QString& groupKeyword, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiGroup* createGroupWithIdBeforeGroup( const QString& groupId, const QString& displayName, const QString& newGroupId, LayoutOptions layout = defaultLayoutOptions() ); + PdmUiGroup* createGroupWithIdBeforeItem( const PdmUiItem* item, const QString& displayName, const QString& newGroupId, @@ -150,11 +162,14 @@ private: const QString& groupKeyword, LayoutOptions layout = defaultLayoutOptions() ); - std::vector m_ordering; ///< The order of groups and fields - std::vector m_createdGroups; ///< Owned PdmUiGroups, for memory management only - bool m_skipRemainingFields; + std::vector m_ordering; + std::vector> m_createdGroups; + std::vector> m_createdLabels; + std::vector> m_createdButtons; + bool m_skipRemainingFields; }; } // End of namespace caf +// Included after PdmUiOrdering, as the group derives from PdmUiOrdering #include "cafPdmUiGroup.h" diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.cpp index cf349da989..344f167b74 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.cpp @@ -3,8 +3,11 @@ #include "MainWindow.h" #include "OptionalFields.h" +#include "cafPdmUiButton.h" #include "cafPdmUiLabelEditor.h" +#include + CAF_PDM_SOURCE_INIT( LabelsAndHyperlinks, "LabelsAndHyperlinks" ); //-------------------------------------------------------------------------------------------------- @@ -21,6 +24,44 @@ LabelsAndHyperlinks::LabelsAndHyperlinks() m_hyperlinkTextField.uiCapability()->setUiEditorTypeName( caf::PdmUiLabelEditor::uiEditorTypeName() ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void LabelsAndHyperlinks::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.addNewLabel( "This is a standalone label without PDM field connection" ); + uiOrdering.addNewLabel( "Labels can display informational text in the GUI" ); + + // Button with text and lambda callback + uiOrdering.addNewButton( "Click Me!", + []() + { + // This lambda will be executed when the button is clicked + auto msgBox = new QMessageBox(); + msgBox->setWindowTitle( "Button Clicked" ); + msgBox->setText( "Hello from the button callback!" ); + msgBox->setAttribute( Qt::WA_DeleteOnClose ); + msgBox->show(); + } ); + + // Button with icon and callback + auto* iconButton = uiOrdering.addNewButton( "Icon Button", + []() + { + auto msgBox = new QMessageBox(); + msgBox->setWindowTitle( "Icon Button" ); + msgBox->setText( "This button has an icon!" ); + msgBox->setAttribute( Qt::WA_DeleteOnClose ); + msgBox->show(); + } ); + iconButton->setIconFromResourceString( ":/cafCommandFeatures/Delete.svg" ); + + uiOrdering.add( &m_labelTextField ); + uiOrdering.add( &m_hyperlinkTextField ); + + uiOrdering.addNewLabel( "Another label at the bottom demonstrating multiple labels" ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.h b/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.h index 6b9062ca44..b6b2e4fa83 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.h +++ b/Fwk/AppFwk/cafTests/cafTestApplication/LabelsAndHyperlinks.h @@ -14,6 +14,7 @@ public: LabelsAndHyperlinks(); protected: + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp index 84f497f18b..22473caeeb 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp @@ -40,9 +40,11 @@ #include "cafPdmChildField.h" #include "cafPdmLogging.h" #include "cafPdmObjectHandle.h" +#include "cafPdmUiButton.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiFieldEditorHelper.h" #include "cafPdmUiFieldHandle.h" +#include "cafPdmUiLabel.h" #include "cafPdmUiListEditor.h" #include "cafPdmUiObjectHandle.h" #include "cafPdmUiOrdering.h" @@ -55,6 +57,8 @@ #include #include #include +#include +#include //-------------------------------------------------------------------------------------------------- /// @@ -172,6 +176,32 @@ int caf::PdmUiFormLayoutObjectEditor::recursivelyConfigureAndUpdateUiOrderingInG currentColumn += itemColumnSpan; sumRowStretch += groupStretchFactor; } + else if ( auto* label = dynamic_cast( currentItem ) ) + { + if ( auto qLabel = findOrCreateLabel( containerWidgetWithGridLayout, label, uiConfigName ) ) + { + parentLayout->addWidget( qLabel, currentRowIndex, currentColumn, 1, itemColumnSpan, Qt::AlignTop ); + currentColumn += itemColumnSpan; + } + else + { + CAF_PDM_LOG_ERROR( QString( "UI Form Layout Editor: Failed to create label for text '%1'." ) + .arg( label->uiName( uiConfigName ) ) ); + } + } + else if ( auto* button = dynamic_cast( currentItem ) ) + { + if ( auto qButton = findOrCreateButton( containerWidgetWithGridLayout, button, uiConfigName ) ) + { + parentLayout->addWidget( qButton, currentRowIndex, currentColumn, 1, itemColumnSpan, button->alignment() ); + currentColumn += itemColumnSpan; + } + else + { + CAF_PDM_LOG_ERROR( QString( "UI Form Layout Editor: Failed to create button for text '%1'." ) + .arg( button->uiName( uiConfigName ) ) ); + } + } else { PdmUiFieldEditorHandle* fieldEditor = nullptr; @@ -350,9 +380,7 @@ QMinimizePanel* caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox( QWidget* QMinimizePanel* groupBox = nullptr; // Find or create groupBox - std::map>::iterator it; - it = m_groupBoxes.find( groupBoxKey ); - + auto it = m_groupBoxes.find( groupBoxKey ); if ( it == m_groupBoxes.end() ) { auto newBoxIt = m_newGroupBoxes.find( groupBoxKey ); @@ -402,6 +430,110 @@ QMinimizePanel* caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox( QWidget* return groupBox; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QLabel* caf::PdmUiFormLayoutObjectEditor::findOrCreateLabel( QWidget* parent, PdmUiLabel* label, const QString& uiConfigName ) +{ + QString labelKey = label->uiName( uiConfigName ); + QLabel* qLabel = nullptr; + + // Find or create label + auto it = m_labels.find( labelKey ); + if ( it == m_labels.end() ) + { + auto newLabelIt = m_newLabels.find( labelKey ); + if ( newLabelIt != m_newLabels.end() ) + { + auto message = "Detected duplicate label with text: " + labelKey; + CAF_PDM_LOG_ERROR( QString( "UI Form Layout Editor: %1. This may cause layout issues. Ensure unique label " + "texts in PdmUiOrdering." ) + .arg( message ) ); + } + + qLabel = new QLabel( parent ); + qLabel->setText( label->uiName( uiConfigName ) ); + qLabel->setWordWrap( true ); + qLabel->setObjectName( labelKey ); + + m_newLabels[labelKey] = qLabel; + } + else + { + qLabel = it->second; + CAF_ASSERT( qLabel ); + m_newLabels[labelKey] = qLabel; + } + + // Update the text to support dynamic label content + qLabel->setText( label->uiName( uiConfigName ) ); + return qLabel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPushButton* caf::PdmUiFormLayoutObjectEditor::findOrCreateButton( QWidget* parent, + PdmUiButton* button, + const QString& uiConfigName ) +{ + QString buttonKey = button->uiName( uiConfigName ); + QPushButton* qButton = nullptr; + + // Find or create button + auto it = m_buttons.find( buttonKey ); + if ( it == m_buttons.end() ) + { + auto newButtonIt = m_newButtons.find( buttonKey ); + if ( newButtonIt != m_newButtons.end() ) + { + auto message = "Detected duplicate button with text: " + buttonKey; + CAF_PDM_LOG_ERROR( QString( "UI Form Layout Editor: %1. This may cause layout issues. Ensure unique button " + "texts in PdmUiOrdering." ) + .arg( message ) ); + } + + qButton = new QPushButton( parent ); + qButton->setText( button->uiName( uiConfigName ) ); + qButton->setObjectName( buttonKey ); + + // Set size policy to size the button to its content rather than fill available space + qButton->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Fixed ); + + // Set icon if available + auto icon = button->uiIcon( uiConfigName ); + if ( icon && !icon->isNull() ) + { + qButton->setIcon( *icon ); + } + + // Connect callback if available + auto callback = button->clickCallback(); + if ( callback ) + { + QObject::connect( qButton, &QPushButton::clicked, [callback]() { callback(); } ); + } + + m_newButtons[buttonKey] = qButton; + } + else + { + qButton = it->second; + CAF_ASSERT( qButton ); + m_newButtons[buttonKey] = qButton; + } + + // Update the text and icon to support dynamic button content + qButton->setText( button->uiName( uiConfigName ) ); + auto icon = button->uiIcon( uiConfigName ); + if ( icon && !icon->isNull() ) + { + qButton->setIcon( *icon ); + } + + return qButton; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -535,6 +667,8 @@ void caf::PdmUiFormLayoutObjectEditor::cleanupBeforeSettingPdmObject() m_fieldViews.clear(); m_newGroupBoxes.clear(); + m_newLabels.clear(); + m_newButtons.clear(); std::map>::iterator groupIt; for ( groupIt = m_groupBoxes.begin(); groupIt != m_groupBoxes.end(); ++groupIt ) @@ -552,6 +686,30 @@ void caf::PdmUiFormLayoutObjectEditor::cleanupBeforeSettingPdmObject() m_groupBoxes.clear(); + std::map>::iterator labelIt; + for ( labelIt = m_labels.begin(); labelIt != m_labels.end(); ++labelIt ) + { + QLabel* label = labelIt->second; + if ( label ) + { + delete label; + } + } + + m_labels.clear(); + + std::map>::iterator buttonIt; + for ( buttonIt = m_buttons.begin(); buttonIt != m_buttons.end(); ++buttonIt ) + { + QPushButton* button = buttonIt->second; + if ( button ) + { + delete button; + } + } + + m_buttons.clear(); + // Note: Layouts are now managed by Qt's parent-child ownership system. // When added to parent layouts via addLayout(), Qt automatically handles cleanup. } @@ -614,6 +772,32 @@ void caf::PdmUiFormLayoutObjectEditor::configureAndUpdateUi( const QString& uiCo } m_groupBoxes = m_newGroupBoxes; + // Clean up unused labels + std::map>::iterator labelMapIt; + for ( labelMapIt = m_labels.begin(); labelMapIt != m_labels.end(); ++labelMapIt ) + { + std::map>::iterator it = m_newLabels.find( labelMapIt->first ); + if ( it == m_newLabels.end() ) + { + // The old label is not present anymore, get rid of it + if ( !labelMapIt->second.isNull() ) delete labelMapIt->second; + } + } + m_labels = m_newLabels; + + // Clean up unused buttons + std::map>::iterator buttonMapIt; + for ( buttonMapIt = m_buttons.begin(); buttonMapIt != m_buttons.end(); ++buttonMapIt ) + { + std::map>::iterator it = m_newButtons.find( buttonMapIt->first ); + if ( it == m_newButtons.end() ) + { + // The old button is not present anymore, get rid of it + if ( !buttonMapIt->second.isNull() ) delete buttonMapIt->second; + } + } + m_buttons = m_newButtons; + // Notify pdm object when widgets have been created caf::PdmUiObjectHandle* uiObject = uiObj( pdmObject() ); if ( uiObject ) diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h index 77b1e2a444..3db6ce0e90 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h @@ -47,11 +47,15 @@ class QMinimizePanel; class QGridLayout; class QWidget; class QVBoxLayout; +class QLabel; +class QPushButton; namespace caf { class PdmUiFieldEditorHandle; class PdmUiGroup; +class PdmUiLabel; +class PdmUiButton; class PdmUiOrdering; //================================================================================================== @@ -86,6 +90,8 @@ protected: int itemColumnSpan ); QMinimizePanel* findOrCreateGroupBox( QWidget* parent, PdmUiGroup* group, const QString& uiConfigName ); + QLabel* findOrCreateLabel( QWidget* parent, PdmUiLabel* label, const QString& uiConfigName ); + QPushButton* findOrCreateButton( QWidget* parent, PdmUiButton* button, const QString& uiConfigName ); PdmUiFieldEditorHandle* findOrCreateFieldEditor( QWidget* parent, PdmUiFieldHandle* field, const QString& uiConfigName ); static void ensureWidgetContainsEmptyGridLayout( QWidget* containerWidget, QMargins contentMargins = QMargins() ); @@ -109,6 +115,10 @@ private: std::map> m_groupBoxes; std::map> m_newGroupBoxes; ///< used temporarily to store the new(complete) set of ///< group boxes + std::map> m_labels; + std::map> m_newLabels; ///< used temporarily to store the new(complete) set of labels + std::map> m_buttons; + std::map> m_newButtons; ///< used temporarily to store the new(complete) set of buttons std::map> m_objectKeywordGroupUiNameExpandedState; };