diff --git a/ApplicationCode/Application/RiaPreferences.cpp b/ApplicationCode/Application/RiaPreferences.cpp index c20e447ffa..5dc851c6a7 100644 --- a/ApplicationCode/Application/RiaPreferences.cpp +++ b/ApplicationCode/Application/RiaPreferences.cpp @@ -59,9 +59,32 @@ void RiaPreferences::SummaryHistoryCurveStyleModeType::setUp() addItem( RiaPreferences::SYMBOLS_AND_LINES, "SYMBOLS_AND_LINES", "Symbols and Lines" ); setDefault( RiaPreferences::SYMBOLS ); } + +template <> +void RiaPreferences::PageSizeEnum::setUp() +{ + addItem( QPageSize::A3, "A3", "A3" ); + addItem( QPageSize::A4, "A4", "A4" ); + addItem( QPageSize::A5, "A5", "A5" ); + addItem( QPageSize::A6, "A6", "A6" ); + addItem( QPageSize::Letter, "LETTER", "US Letter" ); + addItem( QPageSize::Legal, "LEGAL", "US Legal" ); + addItem( QPageSize::Ledger, "LEDGER", "US Ledger" ); + addItem( QPageSize::Tabloid, "TABLOID", "US Tabloid" ); + setDefault( QPageSize::A4 ); +} + +template <> +void RiaPreferences::PageOrientationEnum::setUp() +{ + addItem( QPageLayout::Portrait, "PORTRAIT", "Portrait" ); + addItem( QPageLayout::Landscape, "LANDSCAPE", "Landscape" ); + setDefault( QPageLayout::Portrait ); +} } // namespace caf CAF_PDM_SOURCE_INIT( RiaPreferences, "RiaPreferences" ); + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -337,6 +360,19 @@ RiaPreferences::RiaPreferences( void ) "", "" ); m_useMultipleThreadsWhenLoadingSummaryData.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + + CAF_PDM_InitFieldNoDefault( &m_pageSize, "pageSize", "Page Size", "", "", "" ); + CAF_PDM_InitFieldNoDefault( &m_pageOrientation, "pageOrientation", "Page Orientation", "", "", "" ); + CAF_PDM_InitField( &m_pageLeftMargin, "pageLeftMargin", defaultMarginSize( m_pageSize() ), "Left Margin", "", "", "" ); + CAF_PDM_InitField( &m_pageTopMargin, "pageTopMargin", defaultMarginSize( m_pageSize() ), "Top Margin", "", "", "" ); + CAF_PDM_InitField( &m_pageRightMargin, "pageRightMargin", defaultMarginSize( m_pageSize() ), "Right Margin", "", "", "" ); + CAF_PDM_InitField( &m_pageBottomMargin, + "pageBottomMargin", + defaultMarginSize( m_pageSize() ), + "Bottom Margin", + "", + "", + "" ); } //-------------------------------------------------------------------------------------------------- @@ -467,7 +503,26 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& caf::PdmUiGroup* group = uiOrdering.addNewGroup( "Plot Templates" ); group->add( &m_plotTemplateFolders ); group->add( &m_searchPlotTemplateFoldersRecursively ); + + caf::PdmUiGroup* pageSetup = uiOrdering.addNewGroup( "Page Setup" ); + pageSetup->add( &m_pageSize ); + pageSetup->add( &m_pageOrientation, false ); + pageSetup->add( &m_pageLeftMargin ); + pageSetup->add( &m_pageRightMargin, false ); + pageSetup->add( &m_pageTopMargin ); + pageSetup->add( &m_pageBottomMargin, false ); + + QString unitLabel = " [mm]"; + if ( QPageSize( m_pageSize() ).definitionUnits() == QPageSize::Inch ) + { + unitLabel = " [in]"; + } + m_pageLeftMargin.uiCapability()->setUiName( "Left Margin" + unitLabel ); + m_pageRightMargin.uiCapability()->setUiName( "Right Margin" + unitLabel ); + m_pageTopMargin.uiCapability()->setUiName( "Top Margin" + unitLabel ); + m_pageBottomMargin.uiCapability()->setUiName( "Bottom Margin" + unitLabel ); } + else if ( uiConfigName == RiaPreferences::tabNameScripting() ) { caf::PdmUiGroup* octaveGroup = uiOrdering.addNewGroup( "Octave" ); @@ -581,6 +636,21 @@ void RiaPreferences::initAfterRead() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaPreferences::fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) +{ + if ( changedField == &m_pageSize ) + { + m_pageLeftMargin = defaultMarginSize( m_pageSize() ); + m_pageRightMargin = defaultMarginSize( m_pageSize() ); + m_pageTopMargin = defaultMarginSize( m_pageSize() ); + m_pageBottomMargin = defaultMarginSize( m_pageSize() ); + } +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -629,6 +699,22 @@ QString RiaPreferences::tabNameSystem() return "System"; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaPreferences::defaultMarginSize( QPageSize::PageSizeId pageSizeId ) +{ + QPageSize::Unit unit = QPageSize( pageSizeId ).definitionUnits(); + + if ( unit == QPageSize::Inch ) + { + return 1.0; + } + else + { + return 20.0; + } +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -851,3 +937,17 @@ void RiaPreferences::writePreferencesToApplicationStore() { caf::PdmSettings::writeFieldsToApplicationStore( this ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPageLayout RiaPreferences::defaultPageLayout() const +{ + QPageSize pageSize( m_pageSize() ); + QPageLayout layout( pageSize, + m_pageOrientation(), + QMarginsF( m_pageLeftMargin, m_pageTopMargin, m_pageRightMargin, m_pageBottomMargin ), + (QPageLayout::Unit)pageSize.definitionUnits() ); + layout.setMode( QPageLayout::StandardMode ); + return layout; +} diff --git a/ApplicationCode/Application/RiaPreferences.h b/ApplicationCode/Application/RiaPreferences.h index 8ca7ac0ef2..72d5bb84e1 100644 --- a/ApplicationCode/Application/RiaPreferences.h +++ b/ApplicationCode/Application/RiaPreferences.h @@ -35,6 +35,8 @@ // Include to make Pdm work for cvf::Color #include "cafPdmFieldCvfColor.h" +#include +#include #include #include @@ -66,6 +68,10 @@ public: }; typedef caf::AppEnum SummaryHistoryCurveStyleModeType; + typedef caf::AppEnum PageSizeEnum; + typedef caf::AppEnum PageOrientationEnum; + +public: RiaPreferences( void ); ~RiaPreferences( void ) override; @@ -97,7 +103,8 @@ public: std::map defaultFontSizes() const; - void writePreferencesToApplicationStore(); + void writePreferencesToApplicationStore(); + QPageLayout defaultPageLayout() const; public: // Pdm Fields caf::PdmField> navigationPolicy; @@ -156,6 +163,9 @@ protected: QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly ) override; void initAfterRead() override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue ) override; private: static QString tabNameGeneral(); @@ -165,6 +175,8 @@ private: static QString tabNameExport(); static QString tabNameSystem(); + static double defaultMarginSize( QPageSize::PageSizeId pageSizeId ); + private: caf::PdmChildField m_readerSettings; @@ -184,6 +196,13 @@ private: caf::PdmField m_showSummaryTimeAsLongString; caf::PdmField m_useMultipleThreadsWhenLoadingSummaryData; + caf::PdmField m_pageSize; + caf::PdmField m_pageOrientation; + caf::PdmField m_pageLeftMargin; + caf::PdmField m_pageRightMargin; + caf::PdmField m_pageTopMargin; + caf::PdmField m_pageBottomMargin; + caf::PdmField m_plotTemplateFolders; caf::PdmField m_searchPlotTemplateFoldersRecursively; caf::PdmField m_defaultPlotTemplate; diff --git a/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.cpp index a83b5afcad..d8cb54fd70 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.cpp @@ -20,8 +20,10 @@ #include "RiaGuiApplication.h" #include "RiaLogging.h" +#include "RiaPlotWindowRedrawScheduler.h" #include "RimMainPlotCollection.h" +#include "RimPlotWindow.h" #include "RimProject.h" #include "RimViewWindow.h" #include "RiuPlotMainWindow.h" @@ -33,9 +35,13 @@ #include #include #include +#include #include #include #include +#include +#include +#include CAF_CMD_SOURCE_INIT( RicSnapshotViewToFileFeature, "RicSnapshotViewToFileFeature" ); @@ -72,7 +78,71 @@ void RicSnapshotViewToFileFeature::saveSnapshotAs( const QString& fileName, cons //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicSnapshotViewToFileFeature::saveToFile( const QImage& image, const QString& defaultFileBaseName ) +void RicSnapshotViewToFileFeature::savePlotPDFReportAs( const QString& fileName, RimPlotWindow* plot ) +{ + RiaPlotWindowRedrawScheduler::instance()->performScheduledUpdatesAndReplots(); + QCoreApplication::processEvents(); + QFile pdfFile( fileName ); + if ( pdfFile.open( QIODevice::WriteOnly ) ) + { + const int resolution = RiaGuiApplication::instance()->desktop()->logicalDpiX(); + QPdfWriter pdfPrinter( fileName ); + pdfPrinter.setPageLayout( plot->pageLayout() ); + pdfPrinter.setCreator( QCoreApplication::applicationName() ); + pdfPrinter.setResolution( resolution ); + QPainter painter( &pdfPrinter ); + QRect widgetRect = plot->viewWidget()->contentsRect(); + QRect fullPageRect = pdfPrinter.pageLayout().fullRectPixels( resolution ); + QRect paintRect = pdfPrinter.pageLayout().paintRectPixels( resolution ); + plot->viewWidget()->resize( paintRect.size() ); + plot->renderWindowContent( &painter ); + plot->viewWidget()->resize( widgetRect.size() ); + } + else + { + RiaLogging::error( QString( "Could not write PDF to %1" ).arg( fileName ) ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSnapshotViewToFileFeature::saveViewWindowToFile( RimViewWindow* viewWindow, + const QString& defaultFileBaseName /*= "image" */ ) +{ + RimPlotWindow* plotWindow = dynamic_cast( viewWindow ); + + QString fileName = generateSaveFileName( defaultFileBaseName, plotWindow != nullptr ); + if ( !fileName.isEmpty() ) + { + if ( plotWindow && fileName.endsWith( "PDF", Qt::CaseInsensitive ) ) + { + savePlotPDFReportAs( fileName, plotWindow ); + } + else + { + RicSnapshotViewToFileFeature::saveSnapshotAs( fileName, viewWindow->snapshotWindowContent() ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSnapshotViewToFileFeature::saveImageToFile( const QImage& image, const QString& defaultFileBaseName ) +{ + QString fileName = generateSaveFileName( defaultFileBaseName, false ); + if ( !fileName.isEmpty() ) + { + RicSnapshotViewToFileFeature::saveSnapshotAs( fileName, image ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicSnapshotViewToFileFeature::generateSaveFileName( const QString& defaultFileBaseName /*= "image"*/, + bool supportPDF /*= false */ ) { RiaApplication* app = RiaApplication::instance(); RimProject* proj = app->project(); @@ -88,17 +158,30 @@ void RicSnapshotViewToFileFeature::saveToFile( const QImage& image, const QStrin startPath = app->lastUsedDialogDirectory( "IMAGE_SNAPSHOT" ); } - QString defaultAbsFileName = caf::Utils::constructFullFileName( startPath, defaultFileBaseName, ".png" ); - QString fileName = QFileDialog::getSaveFileName( nullptr, tr( "Export to File" ), defaultAbsFileName ); - if ( fileName.isEmpty() ) + QStringList imageFileExtensions; + imageFileExtensions << "*.png" + << "*.jpg" + << "*.bmp" + << "*.pbm" + << "*.pgm"; + QString fileExtensionFilter = QString( "Images (%1)" ).arg( imageFileExtensions.join( " " ) ); + + if ( supportPDF ) { - return; + fileExtensionFilter += ";;PDF report( *.pdf )"; } - // Remember the directory to next time - app->setLastUsedDialogDirectory( "IMAGE_SNAPSHOT", QFileInfo( fileName ).absolutePath() ); - - RicSnapshotViewToFileFeature::saveSnapshotAs( fileName, image ); + QString defaultAbsFileName = caf::Utils::constructFullFileName( startPath, defaultFileBaseName, ".png" ); + QString fileName = QFileDialog::getSaveFileName( nullptr, + tr( "Export to File" ), + defaultAbsFileName, + fileExtensionFilter ); + if ( !fileName.isEmpty() ) + { + // Remember the directory to next time + app->setLastUsedDialogDirectory( "IMAGE_SNAPSHOT", QFileInfo( fileName ).absolutePath() ); + } + return fileName; } //-------------------------------------------------------------------------------------------------- @@ -142,8 +225,7 @@ void RicSnapshotViewToFileFeature::onActionTriggered( bool isChecked ) return; } - QImage image = viewWindow->snapshotWindowContent(); - saveToFile( image, RicSnapshotFilenameGenerator::generateSnapshotFileName( viewWindow ) ); + saveViewWindowToFile( viewWindow, RicSnapshotFilenameGenerator::generateSnapshotFileName( viewWindow ) ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.h b/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.h index d9013aafa0..478be600ed 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicSnapshotViewToFileFeature.h @@ -20,6 +20,7 @@ #include "cafCmdFeature.h" +class RimPlotWindow; class RimViewWindow; class QImage; @@ -31,9 +32,13 @@ class RicSnapshotViewToFileFeature : public caf::CmdFeature CAF_CMD_HEADER_INIT; public: - static void saveSnapshotAs( const QString& fileName, RimViewWindow* viewWindow ); - static void saveSnapshotAs( const QString& fileName, const QImage& image ); - static void saveToFile( const QImage& image, const QString& defaultFileBaseName = "image" ); + static void saveSnapshotAs( const QString& fileName, RimViewWindow* viewWindow ); + static void saveSnapshotAs( const QString& fileName, const QImage& image ); + static void savePlotPDFReportAs( const QString& fileName, RimPlotWindow* plotWindow ); + + static void saveViewWindowToFile( RimViewWindow* viewWindow, const QString& defaultFileBaseName = "image" ); + static void saveImageToFile( const QImage& image, const QString& defaultFileBaseName = "image" ); + static QString generateSaveFileName( const QString& defaultFileBaseName = "image", bool supportPDF = false ); static QIcon icon(); static QString text(); diff --git a/ApplicationCode/Commands/RicGridStatisticsDialog.cpp b/ApplicationCode/Commands/RicGridStatisticsDialog.cpp index 991369747f..1a49e3c9c2 100644 --- a/ApplicationCode/Commands/RicGridStatisticsDialog.cpp +++ b/ApplicationCode/Commands/RicGridStatisticsDialog.cpp @@ -333,5 +333,5 @@ void RicGridStatisticsDialog::slotScreenShotToFile() { defaultFileBaseName = "Snapshot_Statistics"; } - RicSnapshotViewToFileFeature::saveToFile( snapshotImage, defaultFileBaseName ); + RicSnapshotViewToFileFeature::saveImageToFile( snapshotImage, defaultFileBaseName ); } diff --git a/ApplicationCode/GrpcInterface/Python/setup.py.cmake b/ApplicationCode/GrpcInterface/Python/setup.py.cmake index 3ca3adffc9..c331614596 100644 --- a/ApplicationCode/GrpcInterface/Python/setup.py.cmake +++ b/ApplicationCode/GrpcInterface/Python/setup.py.cmake @@ -19,4 +19,5 @@ setup( license=license, packages=['rips'], package_data={'rips': ['*.py', 'generated/*.py', 'PythonExamples/*.py', 'tests/*.py']} + install_requires=['grpcio>=1.20.0'] ) \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp index 627073c75e..c63b179ec0 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp @@ -56,6 +56,7 @@ #include "RimWellPltPlot.h" #include "RiuCvfOverlayItemWidget.h" +#include "RiuDraggableOverlayFrame.h" #include "RiuQwtPlotWidget.h" #include "cafPdmUiListEditor.h" @@ -1268,10 +1269,12 @@ void RimWellRftPlot::defineCurveColorsAndSymbols( const std::setviewer(), - track->viewer()->canvas() ); + m_ensembleLegendFrames[curveSet] = + new RiuCvfOverlayItemWidget( curveSet->legendConfig()->titledOverlayFrame(), + track->viewer()->canvas(), + track->viewer()->overlayMargins() ); } - m_ensembleLegendFrames[curveSet]->updateFromOverlayItem( curveSet->legendConfig()->titledOverlayFrame() ); + track->viewer()->addOverlayFrame( m_ensembleLegendFrames[curveSet] ); } } diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h index 450980b4a9..02ef894c42 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h @@ -51,7 +51,7 @@ class RigEclipseCaseData; class RiaRftPltCurveDefinition; class RifDataSourceForRftPlt; class RifEclipseRftAddress; -class RiuCvfOverlayItemWidget; +class RiuDraggableOverlayFrame; namespace cvf { @@ -156,8 +156,8 @@ private: caf::PdmPtrField m_wellPathCollection; - caf::PdmChildArrayField m_ensembleCurveSets; - std::map> m_ensembleLegendFrames; + caf::PdmChildArrayField m_ensembleCurveSets; + std::map> m_ensembleLegendFrames; std::map m_dataSourceColors; std::map m_timeStepSymbols; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp index 64efc8d976..a7a4604534 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp @@ -22,6 +22,7 @@ #include "RiaPreferences.h" #include "RifTextDataTableFormatter.h" +#include "RiuDraggableOverlayFrame.h" #include "RiuGridCrossQwtPlot.h" #include "RiuPlotMainWindowTools.h" #include "RiuQwtPlotTools.h" @@ -276,6 +277,37 @@ bool RimGridCrossPlot::showInfoBox() const return m_showInfoBox(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateInfoBox() +{ + if ( m_plotWidget ) + { + if ( m_showInfoBox ) + { + if ( !m_infoBox ) + { + m_infoBox = new RiuDraggableOverlayFrame( m_plotWidget->canvas(), m_plotWidget->overlayMargins() ); + m_infoBox->setAnchorCorner( RiuDraggableOverlayFrame::AnchorCorner::TopRight ); + RiuTextOverlayContentFrame* textFrame = new RiuTextOverlayContentFrame( m_infoBox ); + textFrame->setText( generateInfoBoxText() ); + m_infoBox->setContentFrame( textFrame ); + } + m_plotWidget->addOverlayFrame( m_infoBox ); + } + else + { + if ( m_plotWidget && m_infoBox ) + { + m_plotWidget->removeOverlayFrame( m_infoBox ); + delete m_infoBox; + m_infoBox = nullptr; + } + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -355,28 +387,6 @@ void RimGridCrossPlot::onAxisSelected( int axis, bool toggle ) } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGridCrossPlot::addOrUpdateDataSetLegend( RimGridCrossPlotDataSet* dataSet ) -{ - if ( m_plotWidget ) - { - m_plotWidget->addOrUpdateDataSetLegend( dataSet ); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimGridCrossPlot::removeDataSetLegend( RimGridCrossPlotDataSet* dataSet ) -{ - if ( m_plotWidget ) - { - m_plotWidget->removeDataSetLegend( dataSet ); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -391,6 +401,38 @@ void RimGridCrossPlot::doRemoveFromCollection() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::generateInfoBoxText() const +{ + QStringList curveInfoTexts; + for ( auto dataSet : dataSets() ) + { + QString curveInfoText = dataSet->infoText(); + if ( dataSet->isChecked() && !curveInfoText.isEmpty() ) + { + curveInfoTexts += curveInfoText; + } + } + QStringList infoText; + infoText << QString( "View ID: %1
" ).arg( id() ); + if ( curveInfoTexts.size() > 1 ) + { + infoText += QString( "
    " ); + for ( QString curveInfoText : curveInfoTexts ) + { + infoText += QString( "
  1. %1
  2. " ).arg( curveInfoText ); + } + infoText += QString( "
" ); + } + else if ( curveInfoTexts.size() > 0 ) + { + infoText += curveInfoTexts.front(); + } + return infoText.join( "\n" ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -404,9 +446,9 @@ QWidget* RimGridCrossPlot::createViewWidget( QWidget* mainWindowParent ) { dataSet->setParentQwtPlotNoReplot( m_plotWidget ); } - m_plotWidget->scheduleReplot(); } + m_plotWidget->scheduleReplot(); return m_plotWidget; } @@ -433,6 +475,7 @@ void RimGridCrossPlot::onLoadDataAndUpdate() updateCurveNamesAndPlotTitle(); updatePlot(); + updateInfoBox(); } //-------------------------------------------------------------------------------------------------- @@ -724,6 +767,7 @@ bool RimGridCrossPlot::applyFontSize( RiaDefines::FontSettingType fontSettingTyp if ( forceChange || legendFontSize() == oldFontSize ) { setLegendFontSize( fontSize ); + anyChange = true; } diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h index c5388ad69c..c660a80dc3 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h @@ -32,6 +32,7 @@ class RimPlotAxisPropertiesInterface; class RimPlotAxisProperties; class RimGridCrossPlotDataSet; +class RiuDraggableOverlayFrame; class RiuGridCrossQwtPlot; class RimGridCrossPlotNameConfig : public RimNameConfig @@ -76,6 +77,7 @@ public: QString createAutoName() const override; bool showInfoBox() const; + void updateInfoBox(); caf::PdmFieldHandle* userDescriptionField() override; void detachAllCurves() override; @@ -109,9 +111,6 @@ public: caf::PdmObject* findPdmObjectFromQwtCurve( const QwtPlotCurve* curve ) const override; void onAxisSelected( int axis, bool toggle ) override; - void addOrUpdateDataSetLegend( RimGridCrossPlotDataSet* dataSet ); - void removeDataSetLegend( RimGridCrossPlotDataSet* dataSet ); - protected: QWidget* createViewWidget( QWidget* mainWindowParent = nullptr ) override; void deleteViewWidget() override; @@ -146,7 +145,8 @@ private: void doUpdateLayout() override; void cleanupBeforeClose(); - void doRemoveFromCollection() override; + void doRemoveFromCollection() override; + QString generateInfoBoxText() const; private: caf::PdmField m_showInfoBox; @@ -158,5 +158,6 @@ private: caf::PdmChildArrayField m_crossPlotDataSets; - QPointer m_plotWidget; + QPointer m_plotWidget; + QPointer m_infoBox; }; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp index 64ffe8f4a6..e5428224d8 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp @@ -33,7 +33,9 @@ #include "RigFormationNames.h" #include "RigMainGrid.h" +#include "RiuCvfOverlayItemWidget.h" #include "RiuGridCrossQwtPlot.h" +#include "RiuScalarMapperLegendFrame.h" #include "RimCase.h" #include "RimEclipseCase.h" @@ -57,6 +59,7 @@ #include "cafPdmUiSliderEditor.h" #include "cafPdmUiTreeOrdering.h" #include "cafProgressInfo.h" +#include "cafTitledOverlayFrame.h" #include "cvfScalarMapper.h" #include "cvfqtUtils.h" @@ -133,6 +136,18 @@ RimGridCrossPlotDataSet::RimGridCrossPlotDataSet() setDefaults(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotDataSet::~RimGridCrossPlotDataSet() +{ + if ( m_legendOverlayFrame ) + { + m_legendOverlayFrame->setParent( nullptr ); + delete m_legendOverlayFrame; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1020,11 +1035,20 @@ void RimGridCrossPlotDataSet::updateLegendRange() m_groupingProperty->updateRangesForEmbeddedLegends( m_timeStep() ); } } - parent->addOrUpdateDataSetLegend( this ); + if ( !m_legendOverlayFrame ) + { + m_legendOverlayFrame = new RiuDraggableOverlayFrame( parent->viewer()->canvas(), + parent->viewer()->overlayMargins() ); + } + m_legendOverlayFrame->setContentFrame( legendConfig()->makeLegendFrame() ); + parent->viewer()->addOverlayFrame( m_legendOverlayFrame ); } else { - parent->removeDataSetLegend( this ); + if ( m_legendOverlayFrame ) + { + parent->viewer()->removeOverlayFrame( m_legendOverlayFrame ); + } } } } diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h index 4a4e4482ad..338c0ecd6a 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h @@ -36,6 +36,7 @@ #include #include +#include #include class RifTextDataTableFormatter; @@ -47,11 +48,12 @@ class RimEclipseResultCase; class RimEclipseCellColors; class RimEclipseResultDefinition; class RimRegularLegendConfig; +class RimPlotCellFilterCollection; +class RimPlotCellFilter; +class RiuDraggableOverlayFrame; class QwtPlot; class QwtPlotCurve; class QString; -class RimPlotCellFilterCollection; -class RimPlotCellFilter; class RimGridCrossPlotDataSetNameConfig : public RimNameConfig { @@ -93,7 +95,7 @@ public: public: RimGridCrossPlotDataSet(); - ~RimGridCrossPlotDataSet() = default; + ~RimGridCrossPlotDataSet(); void setCellFilterView( RimGridView* cellFilterView ); void loadDataAndUpdate( bool updateParentPlot ); @@ -188,5 +190,6 @@ private: caf::PdmField m_useCustomColor; caf::PdmField m_customColor; caf::PdmChildField m_plotCellFilterCollection; - ; + + QPointer m_legendOverlayFrame; }; diff --git a/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.cpp b/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.cpp index 1f21d812c7..64323d6948 100644 --- a/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.cpp +++ b/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.cpp @@ -22,6 +22,7 @@ #include "RiuPlotMainWindow.h" #include "RiuPlotMainWindowTools.h" +#include #include #include @@ -299,6 +300,17 @@ void RimMultiPlotWindow::doSetAutoScaleYEnabled( bool enabled ) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMultiPlotWindow::doRenderWindowContent( QPainter* painter ) +{ + if ( m_viewer ) + { + m_viewer->renderTo( painter ); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -426,10 +438,10 @@ QImage RimMultiPlotWindow::snapshotWindowContent() if ( m_viewer ) { - m_viewer->setSelectionsVisible( false ); - QPixmap pix = m_viewer->grab(); - image = pix.toImage(); - m_viewer->setSelectionsVisible( true ); + QPixmap pix( m_viewer->size() ); + QPainter painter( &pix ); + m_viewer->renderTo( &painter ); + image = pix.toImage(); } return image; diff --git a/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.h b/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.h index f425200c08..53a9782649 100644 --- a/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.h +++ b/ApplicationCode/ProjectDataModel/RimMultiPlotWindow.h @@ -129,6 +129,7 @@ private: virtual void updateSubPlotNames(); virtual void updatePlotWindowTitle(); virtual void doSetAutoScaleYEnabled( bool enabled ); + void doRenderWindowContent( QPainter* painter ) override; protected: caf::PdmField m_showPlotWindowTitle; diff --git a/ApplicationCode/ProjectDataModel/RimPlot.cpp b/ApplicationCode/ProjectDataModel/RimPlot.cpp index d1de867dda..3eecaeceb1 100644 --- a/ApplicationCode/ProjectDataModel/RimPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimPlot.cpp @@ -123,3 +123,14 @@ void RimPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const Q updateParentLayout(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlot::doRenderWindowContent( QPainter* painter ) +{ + if ( viewer() ) + { + viewer()->renderTo( painter, viewer()->frameGeometry() ); + } +} diff --git a/ApplicationCode/ProjectDataModel/RimPlot.h b/ApplicationCode/ProjectDataModel/RimPlot.h index 55a3ef6a6c..3d2d302ba5 100644 --- a/ApplicationCode/ProjectDataModel/RimPlot.h +++ b/ApplicationCode/ProjectDataModel/RimPlot.h @@ -93,6 +93,7 @@ protected: private: virtual void doRemoveFromCollection() = 0; + virtual void doRenderWindowContent( QPainter* painter ); protected: caf::PdmField m_rowSpan; diff --git a/ApplicationCode/ProjectDataModel/RimPlotWindow.cpp b/ApplicationCode/ProjectDataModel/RimPlotWindow.cpp index aa689d4dd1..3345909587 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotWindow.cpp +++ b/ApplicationCode/ProjectDataModel/RimPlotWindow.cpp @@ -18,6 +18,7 @@ #include "RimPlotWindow.h" #include "RiaApplication.h" +#include "RiaPlotWindowRedrawScheduler.h" #include "RiaPreferences.h" #include "RicfCommandObject.h" @@ -26,6 +27,8 @@ #include "cafPdmUiComboBoxEditor.h" +#include + CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimPlotWindow, "RimPlotWindow" ); // Do not use. Abstract class //-------------------------------------------------------------------------------------------------- @@ -153,6 +156,28 @@ void RimPlotWindow::updateParentLayout() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotWindow::renderWindowContent( QPainter* painter ) +{ + doRenderWindowContent( painter ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPageLayout RimPlotWindow::pageLayout() const +{ + QPageLayout defaultPageLayout = RiaApplication::instance()->preferences()->defaultPageLayout(); + QPageLayout customPageLayout; + if ( hasCustomPageLayout( &customPageLayout ) ) + { + return customPageLayout; + } + return defaultPageLayout; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -218,6 +243,14 @@ void RimPlotWindow::uiOrderingForLegendSettings( QString uiConfigName, caf::PdmU uiOrdering.add( &m_legendFontSize ); } +//-------------------------------------------------------------------------------------------------- +/// Re-implement this in sub classes to provide a custom page layout for printing/PDF +//-------------------------------------------------------------------------------------------------- +bool RimPlotWindow::hasCustomPageLayout( QPageLayout* customPageLayout ) const +{ + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimPlotWindow.h b/ApplicationCode/ProjectDataModel/RimPlotWindow.h index 82eba72165..c7f7db4aee 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotWindow.h +++ b/ApplicationCode/ProjectDataModel/RimPlotWindow.h @@ -24,6 +24,8 @@ #include "cafPdmFieldHandle.h" #include "cafPdmObject.h" +#include + class RimProject; class QwtPlotCurve; @@ -57,6 +59,9 @@ public: void updateLayout(); void updateParentLayout(); + void renderWindowContent( QPainter* painter ); + QPageLayout pageLayout() const; + protected: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, @@ -69,6 +74,8 @@ protected: private: virtual void doUpdateLayout() {} + virtual bool hasCustomPageLayout( QPageLayout* customPageLayout ) const; + virtual void doRenderWindowContent( QPainter* painter ) = 0; private: friend class RimProject; diff --git a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp index 7bd6b9c474..4677d4e741 100644 --- a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp @@ -38,6 +38,8 @@ #include "RimWellMeasurementInView.h" #include "RimWellRftEnsembleCurveSet.h" #include "RimWellRftPlot.h" +#include "RiuCategoryLegendFrame.h" +#include "RiuScalarMapperLegendFrame.h" #include "cafCategoryLegend.h" #include "cafCategoryMapper.h" @@ -148,6 +150,7 @@ RimRegularLegendConfig::RimRegularLegendConfig() "", "The number of significant digits displayed in the legend numbers", "" ); + m_significantDigitsInData = m_precision; CAF_PDM_InitField( &m_tickNumberFormat, "TickNumberFormat", caf::AppEnum( FIXED ), @@ -312,6 +315,8 @@ void RimRegularLegendConfig::fieldChangedByUi( const caf::PdmFieldHandle* change //-------------------------------------------------------------------------------------------------- void RimRegularLegendConfig::updateLegend() { + m_significantDigitsInData = m_precision; + double adjustedMin = cvf::UNDEFINED_DOUBLE; double adjustedMax = cvf::UNDEFINED_DOUBLE; @@ -461,7 +466,9 @@ void RimRegularLegendConfig::updateLegend() { numDecimalDigits -= static_cast( decadesInRange ); } - m_scalarMapperLegend->setTickPrecision( cvf::Math::clamp( numDecimalDigits, 0, 20 ) ); + numDecimalDigits = cvf::Math::clamp( numDecimalDigits, 0, 20 ); + m_significantDigitsInData = numDecimalDigits; + m_scalarMapperLegend->setTickPrecision( numDecimalDigits ); RiaApplication* app = RiaApplication::instance(); RiaPreferences* preferences = app->preferences(); @@ -762,7 +769,9 @@ double RimRegularLegendConfig::categoryValueFromCategoryName( const QString& cat //-------------------------------------------------------------------------------------------------- void RimRegularLegendConfig::setTitle( const QString& title ) { - auto cvfTitle = cvfqt::Utils::toString( title ); + m_title = title; + + auto cvfTitle = cvfqt::Utils::toString( m_title ); m_scalarMapperLegend->setTitle( cvfTitle ); m_categoryLegend->setTitle( cvfTitle ); } @@ -805,6 +814,24 @@ const caf::TitledOverlayFrame* RimRegularLegendConfig::titledOverlayFrame() cons } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAbstractLegendFrame* RimRegularLegendConfig::makeLegendFrame() +{ + if ( m_currentScalarMapper == m_categoryMapper ) + { + return new RiuCategoryLegendFrame( nullptr, m_title, m_categoryMapper.p() ); + } + else + { + auto legend = new RiuScalarMapperLegendFrame( nullptr, m_title, m_currentScalarMapper.p() ); + legend->setTickFormat( m_tickNumberFormat() ); + legend->setTickPrecision( m_significantDigitsInData ); + return legend; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h index c1484b93ef..c312e6fe9d 100644 --- a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h +++ b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h @@ -48,6 +48,7 @@ class OverlayScalarMapperLegend; class Rim3dView; class RimEnsembleCurveSet; +class RiuAbstractLegendFrame; //================================================================================================== /// @@ -148,6 +149,7 @@ public: const caf::TitledOverlayFrame* titledOverlayFrame() const override; caf::TitledOverlayFrame* titledOverlayFrame() override; + RiuAbstractLegendFrame* makeLegendFrame(); RangeModeType rangeMode() const; static cvf::Color3ubArray colorArrayFromColorType( ColorRangesType colorType ); @@ -170,9 +172,6 @@ private: friend class RimViewLinker; - caf::OverlayScalarMapperLegend* getOrCreateScalarMapperLegend(); - caf::CategoryLegend* getOrCreateCategoryLegend(); - private: cvf::ref m_linDiscreteScalarMapper; cvf::ref m_logDiscreteScalarMapper; @@ -211,4 +210,7 @@ private: caf::PdmField m_userDefinedMinValue; caf::PdmField> m_colorRangeMode; caf::PdmField> m_mappingMode; + + QString m_title; + int m_significantDigitsInData; }; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index 697bc027df..16b57b5194 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -693,26 +693,6 @@ void RimWellLogPlot::defineEditorAttribute( const caf::PdmFieldHandle* field, } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QImage RimWellLogPlot::snapshotWindowContent() -{ - QImage image; - - if ( m_viewer ) - { - RiuWellLogPlot* wellLogViewer = dynamic_cast( m_viewer.data() ); - CAF_ASSERT( wellLogViewer ); - bool isScrollbarVisible = wellLogViewer->isScrollbarVisible(); - wellLogViewer->setScrollbarVisible( false ); - image = RimMultiPlotWindow::snapshotWindowContent(); - wellLogViewer->setScrollbarVisible( isScrollbarVisible ); - } - - return image; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index da64dc1944..1516eaf8c1 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -122,8 +122,6 @@ protected: QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; - QImage snapshotWindowContent() override; - private: void updateSubPlotNames() override; void updatePlotWindowTitle() override; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp index 89c2334f99..d4683b6728 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp @@ -21,6 +21,7 @@ #include "RiaColorTables.h" #include "RiaGuiApplication.h" #include "RiaStatisticsTools.h" +#include "RiuAbstractLegendFrame.h" #include "SummaryPlotCommands/RicSummaryCurveCreator.h" @@ -47,6 +48,7 @@ #include "RimSummaryPlot.h" #include "RiuCvfOverlayItemWidget.h" +#include "RiuDraggableOverlayFrame.h" #include "RiuPlotMainWindow.h" #include "RiuQwtPlotCurve.h" #include "RiuSummaryCurveDefSelectionDialog.h" @@ -383,7 +385,7 @@ RimRegularLegendConfig* RimEnsembleCurveSet::legendConfig() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QFrame* RimEnsembleCurveSet::legendFrame() const +RiuDraggableOverlayFrame* RimEnsembleCurveSet::legendFrame() const { return m_legendOverlayFrame; } @@ -888,10 +890,10 @@ void RimEnsembleCurveSet::updateCurveColors() { if ( !m_legendOverlayFrame ) { - m_legendOverlayFrame = new RiuCvfOverlayItemWidget( plot->viewer(), plot->viewer()->canvas() ); + m_legendOverlayFrame = new RiuDraggableOverlayFrame( plot->viewer()->canvas(), + plot->viewer()->overlayMargins() ); } - m_legendOverlayFrame->updateFromOverlayItem( m_legendConfig()->titledOverlayFrame() ); - plot->viewer()->addOverlayFrame( m_legendOverlayFrame ); + m_legendOverlayFrame->setContentFrame( m_legendConfig->makeLegendFrame() ); } else { diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h index 4e52153ee0..3eb5844e78 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h @@ -52,7 +52,7 @@ class RimSummaryCurveAutoName; class RimEnsembleCurveFilterCollection; class RimEnsembleStatistics; class RimEnsembleStatisticsCase; -class RiuCvfOverlayItemWidget; +class RiuDraggableOverlayFrame; class QwtPlot; class QwtPlotCurve; @@ -108,8 +108,8 @@ public: RimRegularLegendConfig* legendConfig(); - void updateEnsembleLegendItem(); - QFrame* legendFrame() const; + void updateEnsembleLegendItem(); + RiuDraggableOverlayFrame* legendFrame() const; void updateAllCurves(); void updateStatisticsCurves(); @@ -190,8 +190,8 @@ private: caf::PdmProxyValueField m_autoGeneratedName; caf::PdmChildField m_summaryAddressNameTools; - QwtPlotCurve* m_qwtPlotCurveForLegendText; - QPointer m_legendOverlayFrame; + QwtPlotCurve* m_qwtPlotCurveForLegendText; + QPointer m_legendOverlayFrame; std::unique_ptr m_ensembleStatCase; diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index 3e959e7df5..b3e535cfbc 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -87,6 +87,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h ${CMAKE_CURRENT_LIST_DIR}/RiuMdiMaximizeWindowGuard.h ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindowTools.h ${CMAKE_CURRENT_LIST_DIR}/RiuComparisonViewMover.h +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractOverlayContentFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractLegendFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuCategoryLegendFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuScalarMapperLegendFrame.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -173,6 +177,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMdiMaximizeWindowGuard.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindowTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuComparisonViewMover.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractOverlayContentFrame.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractLegendFrame.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuCategoryLegendFrame.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuScalarMapperLegendFrame.cpp ) list(APPEND CODE_HEADER_FILES @@ -223,6 +231,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuExpressionContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuCalculationsContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuMohrsCirclePlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractOverlayContentFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuAbstractLegendFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuCategoryLegendFrame.h +${CMAKE_CURRENT_LIST_DIR}/RiuScalarMapperLegendFrame.h ) list(APPEND QT_UI_FILES diff --git a/ApplicationCode/UserInterface/RiuAbstractLegendFrame.cpp b/ApplicationCode/UserInterface/RiuAbstractLegendFrame.cpp new file mode 100644 index 0000000000..c852890a48 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAbstractLegendFrame.cpp @@ -0,0 +1,177 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RiuAbstractLegendFrame.h" + +#include +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAbstractLegendFrame::RiuAbstractLegendFrame( QWidget* parent, const QString& title ) + : RiuAbstractOverlayContentFrame( parent ) + , m_title( title ) +{ + setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Maximum ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuAbstractLegendFrame::sizeHint() const +{ + LayoutInfo layout( QSize( 200, 200 ) ); // Use default size + layoutInfo( &layout ); + + QFontMetrics fontMetrics( this->font() ); + QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); + + int preferredContentHeight = titleLines.size() * layout.lineSpacing + labelCount() * layout.lineSpacing; + int preferredHeight = preferredContentHeight + layout.margins.top() + layout.margins.bottom(); + + int maxTickTextWidth = 0; + for ( int i = 0; i < labelCount(); ++i ) + { + QString valueString = label( i ); + int textWidth = fontMetrics.boundingRect( valueString ).width(); + maxTickTextWidth = std::max( maxTickTextWidth, textWidth ); + } + + int preferredWidth = layout.tickEndX + layout.margins.left() + layout.margins.right() + layout.tickTextLeadSpace + + maxTickTextWidth; + + preferredWidth = std::max( preferredWidth, fontMetrics.boundingRect( m_title ).width() ); + preferredWidth = std::min( preferredWidth, 400 ); + + return QSize( preferredWidth, preferredHeight ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuAbstractLegendFrame::minimumSizeHint() const +{ + LayoutInfo layout( QSize( 200, 200 ) ); // Use default size + layoutInfo( &layout ); + + QFontMetrics fontMetrics( this->font() ); + QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); + + int preferredContentHeight = titleLines.size() * layout.lineSpacing + 2 * layout.lineSpacing; + int preferredHeight = preferredContentHeight + layout.margins.top() + layout.margins.bottom(); + + int firstTextWidth = fontMetrics.boundingRect( label( 0 ) ).width(); + int lastTextWidth = fontMetrics.boundingRect( label( labelCount() - 1 ) ).width(); + int maxTickTextWidth = std::max( firstTextWidth, lastTextWidth ); + + int preferredWidth = layout.tickEndX + layout.margins.left() + layout.margins.right() + layout.tickTextLeadSpace + + maxTickTextWidth; + + preferredWidth = std::max( preferredWidth, fontMetrics.boundingRect( m_title ).width() ); + preferredWidth = std::min( preferredWidth, 400 ); + + return QSize( preferredWidth, preferredHeight ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAbstractLegendFrame::renderTo( QPainter* painter, const QRect& targetRect ) +{ + LayoutInfo layout( QSize( targetRect.width(), targetRect.height() ) ); + layoutInfo( &layout ); + + painter->save(); + painter->translate( targetRect.topLeft() ); + QPoint titlePos( layout.margins.left(), layout.margins.top() + layout.lineSpacing / 2 ); + painter->drawText( titlePos, m_title ); + + QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); + + std::vector> visibleTickLabels = visibleLabels( layout ); + for ( auto tickLabel : visibleTickLabels ) + { + painter->drawText( tickLabel.first, tickLabel.second ); + } + + // Render color bar as one colored rectangle per color interval + for ( int i = 0; i < rectCount(); ++i ) + { + renderRect( painter, layout, i ); + } + painter->drawRect( layout.colorBarRect ); + // painter->drawLine( QPointF( layout.tickMidX, layout.tickYPixelPos->get( i ) ), + // QPointF( layout.tickMidX, layout.tickYPixelPos->get( i + 1 ) ) ); + + painter->restore(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAbstractLegendFrame::paintEvent( QPaintEvent* e ) +{ + QPainter painter( this ); + renderTo( &painter, e->rect() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RiuAbstractLegendFrame::visibleLabels( const LayoutInfo& layout ) const +{ + const int textX = layout.tickEndX + layout.tickTextLeadSpace; + + const double overlapTolerance = 1.1 * layout.charHeight; + int lastVisibleTextY = 0; + + std::vector> visibleTickLabels; + + int numLabels = labelCount(); + for ( int i = 0; i < numLabels; i++ ) + { + int textY = labelPixelPosY( layout, i ); + + // Always draw first and last tick label. For all others, skip drawing if text ends up + // on top of the previous label. + if ( i != 0 && i != ( numLabels - 1 ) ) + { + if ( std::fabs( static_cast( textY - lastVisibleTextY ) ) < overlapTolerance ) + { + continue; + } + // Make sure it does not overlap the last tick as well + + int lastTickY = layout.colorBarRect.bottom(); + + if ( std::fabs( static_cast( lastTickY - textY ) ) < overlapTolerance ) + { + continue; + } + } + + QString valueString = label( numLabels - i - 1 ); + QPoint pos( textX, textY ); + + lastVisibleTextY = textY; + visibleTickLabels.push_back( {pos, valueString} ); + } + return visibleTickLabels; +} diff --git a/ApplicationCode/UserInterface/RiuAbstractLegendFrame.h b/ApplicationCode/UserInterface/RiuAbstractLegendFrame.h new file mode 100644 index 0000000000..17a1e20c53 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAbstractLegendFrame.h @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RiuAbstractOverlayContentFrame.h" + +#include +#include + +class RiuAbstractLegendFrame : public RiuAbstractOverlayContentFrame +{ + Q_OBJECT + +public: + RiuAbstractLegendFrame( QWidget* parent, const QString& title ); + + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + + void renderTo( QPainter* painter, const QRect& targetRect ) override; + +protected: + struct LayoutInfo + { + LayoutInfo( const QSize& size ) + { + charHeight = 0; + charAscent = 0; + lineSpacing = 0; + margins = QMargins( 0, 0, 0, 0 ); + tickEndX = 0; + tickStartX = 0; + tickMidX = 0; + + overallLegendSize = size; + } + + int charHeight; + int charAscent; + int lineSpacing; + QMargins margins; + int tickStartX, tickMidX, tickEndX; + int tickTextLeadSpace; + + QRect colorBarRect; + + std::vector tickYPixelPos; + + QSize overallLegendSize; + }; + + void paintEvent( QPaintEvent* e ) override; + std::vector> visibleLabels( const LayoutInfo& layout ) const; + +private: + virtual void layoutInfo( LayoutInfo* layout ) const = 0; + virtual QString label( int index ) const = 0; + virtual int labelPixelPosY( const LayoutInfo& layout, int index ) const = 0; + virtual int labelCount() const = 0; + virtual int rectCount() const = 0; + + virtual void renderRect( QPainter* painter, const LayoutInfo& layout, int rectIndex ) const = 0; + +protected: + QString m_title; +}; diff --git a/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.cpp b/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.cpp new file mode 100644 index 0000000000..5aad48bde5 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.cpp @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RiuAbstractOverlayContentFrame.h" + +#include +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAbstractOverlayContentFrame::RiuAbstractOverlayContentFrame( QWidget* parent /*= nullptr */ ) + : QFrame( parent ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAbstractOverlayContentFrame::~RiuAbstractOverlayContentFrame() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuTextOverlayContentFrame::RiuTextOverlayContentFrame( QWidget* parent /*= nullptr */ ) + : RiuAbstractOverlayContentFrame( parent ) +{ + QVBoxLayout* layout = new QVBoxLayout( this ); + layout->setContentsMargins( 8, 8, 8, 8 ); + m_textLabel = new QLabel; + layout->addWidget( m_textLabel ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTextOverlayContentFrame::setText( const QString& text ) +{ + m_textLabel->setText( text ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuTextOverlayContentFrame::renderTo( QPainter* painter, const QRect& targetRect ) +{ + painter->save(); + painter->translate( targetRect.topLeft() + QPoint( this->contentsMargins().left(), this->contentsMargins().top() ) ); + painter->setFont( m_textLabel->font() ); + + QTextDocument td; + td.setHtml( m_textLabel->text() ); + td.drawContents( painter ); + + painter->restore(); +} diff --git a/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.h b/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.h new file mode 100644 index 0000000000..abad43b7e1 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAbstractOverlayContentFrame.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 +#include +#include + +class QLabel; + +class RiuAbstractOverlayContentFrame : public QFrame +{ + Q_OBJECT +public: + RiuAbstractOverlayContentFrame( QWidget* parent = nullptr ); + ~RiuAbstractOverlayContentFrame(); + + virtual void renderTo( QPainter* painter, const QRect& targetRect ) = 0; +}; + +class RiuTextOverlayContentFrame : public RiuAbstractOverlayContentFrame +{ + Q_OBJECT +public: + RiuTextOverlayContentFrame( QWidget* parent = nullptr ); + + void setText( const QString& text ); + void renderTo( QPainter* painter, const QRect& targetRect ) override; + +private: + QPointer m_textLabel; +}; diff --git a/ApplicationCode/UserInterface/RiuCategoryLegendFrame.cpp b/ApplicationCode/UserInterface/RiuCategoryLegendFrame.cpp new file mode 100644 index 0000000000..7c06932acf --- /dev/null +++ b/ApplicationCode/UserInterface/RiuCategoryLegendFrame.cpp @@ -0,0 +1,105 @@ +#include "RiuCategoryLegendFrame.h" + +#include "cafCategoryLegend.h" + +#include "cvfqtUtils.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCategoryLegendFrame::RiuCategoryLegendFrame( QWidget* parent, const QString& title, caf::CategoryMapper* categoryMapper ) + : RiuAbstractLegendFrame( parent, title ) + , m_categoryMapper( categoryMapper ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuCategoryLegendFrame::~RiuCategoryLegendFrame() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCategoryLegendFrame::layoutInfo( LayoutInfo* layout ) const +{ + QFontMetrics fontMetrics( this->font() ); + QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); + + layout->charHeight = fontMetrics.height(); + layout->charAscent = fontMetrics.ascent(); + layout->lineSpacing = ( fontMetrics.lineSpacing() * 3 ) / 2; + layout->margins = QMargins( 8, 8, 8, 8 ); + layout->tickTextLeadSpace = 5; + + int colorBarWidth = 25; + int colorBarHeight = layout->overallLegendSize.height() - layout->margins.top() - layout->margins.bottom() - + titleLines.size() * layout->lineSpacing; + + int colorBarStartY = layout->margins.top() + titleLines.size() * layout->lineSpacing; + + layout->colorBarRect = QRect( layout->margins.left(), colorBarStartY, colorBarWidth, colorBarHeight ); + + layout->tickStartX = layout->margins.left(); + layout->tickMidX = layout->margins.left() + layout->colorBarRect.width(); + layout->tickEndX = layout->tickMidX + 5; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiuCategoryLegendFrame::label( int index ) const +{ + return cvfqt::Utils::toQString( m_categoryMapper->textForCategoryIndex( index ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuCategoryLegendFrame::labelCount() const +{ + return (int)m_categoryMapper->categoryCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuCategoryLegendFrame::rectCount() const +{ + return (int)m_categoryMapper->categoryCount(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCategoryLegendFrame::renderRect( QPainter* painter, const LayoutInfo& layout, int index ) const +{ + int categoryIndex = static_cast( rectCount() - index - 1u ); + float categoryHeight = static_cast( layout.colorBarRect.height() ) / labelCount(); + float pos = ( categoryIndex + 0.5 ) * categoryHeight / layout.colorBarRect.height(); + float domainValue = m_categoryMapper->domainValue( pos ); + cvf::Color3ub clr = m_categoryMapper->mapToColor( domainValue ); + // qDebug() << "Plot Legend: " << pos << " and " << domainValue << " = " << clr.r() << ", " << clr.g() << ", " + // << clr.b(); + QColor color( clr.r(), clr.g(), clr.b() ); + + int yStart = layout.colorBarRect.top() + static_cast( index * categoryHeight ); + int yEnd = layout.colorBarRect.top() + static_cast( ( index + 1 ) * categoryHeight ); + + QRect rect( QPoint( layout.tickStartX, yStart ), QPoint( layout.tickMidX, yEnd ) ); + painter->fillRect( rect, QBrush( color ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuCategoryLegendFrame::labelPixelPosY( const LayoutInfo& layout, int index ) const +{ + float categoryHeight = static_cast( layout.colorBarRect.height() ) / labelCount(); + int textY = static_cast( layout.colorBarRect.top() + index * categoryHeight + categoryHeight / 2 ); + textY += layout.charAscent / 2; + return textY; +} diff --git a/ApplicationCode/UserInterface/RiuCategoryLegendFrame.h b/ApplicationCode/UserInterface/RiuCategoryLegendFrame.h new file mode 100644 index 0000000000..933c1045dd --- /dev/null +++ b/ApplicationCode/UserInterface/RiuCategoryLegendFrame.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RiuAbstractLegendFrame.h" + +#include "cvfObject.h" + +#include "cafCategoryMapper.h" + +#include +#include + +class QFont; +class QPaintEvent; +class QPainter; +class QRect; + +class RiuCategoryLegendFrame : public RiuAbstractLegendFrame +{ + Q_OBJECT + +public: + RiuCategoryLegendFrame( QWidget* parent, const QString& title, caf::CategoryMapper* categoryMapper ); + ~RiuCategoryLegendFrame(); + +private: + void layoutInfo( LayoutInfo* layout ) const override; + QString label( int index ) const override; + int labelCount() const override; + int rectCount() const override; + void renderRect( QPainter* painter, const LayoutInfo& layout, int rectIndex ) const override; + int labelPixelPosY( const LayoutInfo& layout, int index ) const override; + +private: + cvf::cref m_categoryMapper; +}; diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp index 45dab304fa..167b360bda 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp @@ -20,6 +20,7 @@ #include "RiaGuiApplication.h" +#include "cafAssert.h" #include "cafTitledOverlayFrame.h" #include "cafViewer.h" @@ -30,23 +31,24 @@ #include "cvfRendering.h" #include "cvfqtUtils.h" -#include -#include -#include #include +#include #include #include #include #include "glew/GL/glew.h" + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget( QWidget* parent /*=0*/, QWidget* widgetToSnapTo ) - : RiuDraggableOverlayFrame( parent, widgetToSnapTo ) +RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget( caf::TitledOverlayFrame* overlayItem, + QWidget* parent, + const int snapMargins, + const QColor& backgroundColor /*= QColor( 255, 255, 255, 100 ) */ ) + : RiuDraggableOverlayFrame( parent, snapMargins, backgroundColor ) + , m_overlayItem( overlayItem ) { - this->layout()->setMargin( 0 ); - this->layout()->setSpacing( 0 ); } //-------------------------------------------------------------------------------------------------- @@ -57,19 +59,25 @@ RiuCvfOverlayItemWidget::~RiuCvfOverlayItemWidget() {} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuCvfOverlayItemWidget::updateFromOverlayItem( caf::TitledOverlayFrame* item ) +QSize RiuCvfOverlayItemWidget::sizeHint() const { - item->setRenderSize( item->preferredSize() ); + auto preferredSize = const_cast( m_overlayItem.p() )->preferredSize(); + return QSize( preferredSize.x(), preferredSize.y() ); +} - unsigned int width = item->renderSize().x(); - unsigned int height = item->renderSize().y(); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCvfOverlayItemWidget::renderTo( QPainter* painter, const QRect& paintRect, double scaleX, double scaleY ) +{ + unsigned int width = static_cast( paintRect.width() ); + unsigned int height = static_cast( paintRect.height() ); + + m_overlayItem->setRenderSize( cvf::Vec2ui( width, height ) ); QGLFormat glFormat; glFormat.setDirectRendering( RiaGuiApplication::instance()->useShaders() ); - // Enforce no border to avoid - item->setBackgroundFrameColor( cvf::Color4f( 0, 0, 0, 0 ) ); - caf::Viewer* viewer = new caf::Viewer( glFormat, nullptr ); cvf::OpenGLContext* cvfOglContext = viewer->cvfOpenGLContext(); viewer->resize( width, height ); @@ -77,8 +85,8 @@ void RiuCvfOverlayItemWidget::updateFromOverlayItem( caf::TitledOverlayFrame* it // Create a rendering cvf::ref rendering = new cvf::Rendering; - item->setLayoutFixedPosition( {0, 0} ); - rendering->addOverlayItem( item ); + m_overlayItem->setLayoutFixedPosition( {0, 0} ); + rendering->addOverlayItem( m_overlayItem.p() ); rendering->camera()->setViewport( 0, 0, width, height ); rendering->camera()->viewport()->setClearColor( {1, 1, 1, 0} ); @@ -108,7 +116,7 @@ void RiuCvfOverlayItemWidget::updateFromOverlayItem( caf::TitledOverlayFrame* it renderingSequence->render( cvfOglContext ); - // Read data from framebuffer + // Read data from frame buffer cvf::UByteArray arr( 4 * width * height ); glReadPixels( 0, 0, static_cast( width ), static_cast( height ), GL_RGBA, GL_UNSIGNED_BYTE, arr.ptr() ); @@ -125,7 +133,17 @@ void RiuCvfOverlayItemWidget::updateFromOverlayItem( caf::TitledOverlayFrame* it delete viewer; - m_overlayItemLabel->setPixmap( pixmap ); - this->setMinimumSize( QSize( width, height ) ); - this->resize( QSize( width, height ) ); + painter->save(); + painter->drawPixmap( paintRect.topLeft(), pixmap ); + painter->restore(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuCvfOverlayItemWidget::paintEvent( QPaintEvent* e ) +{ + QRect paintRect = e->rect(); + QPainter painter( this ); + renderTo( &painter, paintRect, 1.0, 1.0 ); } diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h index 0fce0c339e..2f0049b32c 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h @@ -20,9 +20,12 @@ #include "RiuDraggableOverlayFrame.h" +#include "cvfObject.h" + +#include +#include #include -class QLabel; namespace caf { class TitledOverlayFrame; @@ -37,11 +40,18 @@ class RiuCvfOverlayItemWidget : public RiuDraggableOverlayFrame { Q_OBJECT public: - explicit RiuCvfOverlayItemWidget( QWidget* parent = nullptr, QWidget* widgetToSnapTo = nullptr ); + explicit RiuCvfOverlayItemWidget( caf::TitledOverlayFrame* overlayItem, + QWidget* parent, + const int snapMargins, + const QColor& backgroundColor = QColor( 255, 255, 255, 100 ) ); ~RiuCvfOverlayItemWidget() override; - void updateFromOverlayItem( caf::TitledOverlayFrame* item ); + QSize sizeHint() const override; + void renderTo( QPainter* painter, const QRect& paintRect, double scaleX, double scaleY ); - // virtual QSize sizeHint() const override; - // virtual QSize minimumSizeHint() const override; +protected: + void paintEvent( QPaintEvent* e ) override; + +private: + cvf::ref m_overlayItem; }; diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp index b25995a238..b55daa5442 100644 --- a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp @@ -20,15 +20,18 @@ #include #include +#include +#include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuDraggableOverlayFrame::RiuDraggableOverlayFrame( QWidget* parent, QWidget* widgetToSnapTo, const QColor& backgroundColor ) +RiuDraggableOverlayFrame::RiuDraggableOverlayFrame( QWidget* parent, const int snapMargins, const QColor& backgroundColor ) : QFrame( parent ) + , m_anchorCorner( AnchorCorner::TopLeft ) { - RiuWidgetDragger* dragger = new RiuWidgetDragger( this, widgetToSnapTo ); + m_widgetDragger = new RiuWidgetDragger( this, snapMargins ); QPalette pal = this->palette(); pal.setColor( QPalette::Window, backgroundColor ); @@ -40,22 +43,84 @@ RiuDraggableOverlayFrame::RiuDraggableOverlayFrame( QWidget* parent, QWidget* wi dropShadowEffect->setBlurRadius( 3.0 ); dropShadowEffect->setColor( QColor( 100, 100, 100, 100 ) ); setGraphicsEffect( dropShadowEffect ); - - auto hblayout = new QVBoxLayout( this ); - this->setLayout( hblayout ); - - m_overlayItemLabel = new QLabel( this ); - hblayout->addWidget( m_overlayItemLabel ); - m_overlayItemLabel->setObjectName( "OverlayFrameLabel" ); - m_overlayItemLabel->setGraphicsEffect( nullptr ); - m_overlayItemLabel->setAlignment( Qt::AlignTop | Qt::AlignLeft ); - dragger->addWidget( m_overlayItemLabel ); + this->setContentsMargins( 1, 1, 1, 1 ); + m_layout = new QVBoxLayout( this ); + m_layout->setContentsMargins( 0, 0, 0, 0 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QLabel* RiuDraggableOverlayFrame::label() +RiuAbstractOverlayContentFrame* RiuDraggableOverlayFrame::contentFrame() { - return m_overlayItemLabel; + return m_contentFrame; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuDraggableOverlayFrame::setContentFrame( RiuAbstractOverlayContentFrame* contentFrame ) +{ + if ( m_contentFrame ) + { + m_layout->removeWidget( m_contentFrame ); + m_contentFrame->setParent( nullptr ); // TODO: check if both removeWidget and setParent is necessary + delete m_contentFrame; + m_contentFrame = nullptr; + } + + m_contentFrame = contentFrame; + m_layout->addWidget( m_contentFrame ); + this->adjustSize(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuDraggableOverlayFrame::renderTo( QPainter* painter, const QRect& targetRect ) +{ + if ( m_contentFrame ) + { + painter->save(); + painter->fillRect( targetRect, this->palette().color( QWidget::backgroundRole() ) ); + QRect contentRect = targetRect; + contentRect.adjust( -1, -1, -1, -1 ); + m_contentFrame->renderTo( painter, contentRect ); + painter->drawRect( targetRect ); + painter->restore(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuDraggableOverlayFrame::setAnchorCorner( AnchorCorner corner ) +{ + m_anchorCorner = corner; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuDraggableOverlayFrame::AnchorCorner RiuDraggableOverlayFrame::anchorCorner() const +{ + return m_anchorCorner; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuDraggableOverlayFrame::sizeHint() const +{ + QSize contentSize = m_contentFrame->sizeHint(); + return QSize( contentSize.width() + 2, contentSize.height() + 2 ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuDraggableOverlayFrame::minimumSizeHint() const +{ + QSize contentSize = m_contentFrame->minimumSizeHint(); + return QSize( contentSize.width() + 2, contentSize.height() + 2 ); } diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h index 51b59e873f..1f930e0176 100644 --- a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h @@ -17,21 +17,44 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once +#include "RiuAbstractOverlayContentFrame.h" + #include +#include #include class QColor; -class QLabel; +class QVBoxLayout; +class RiuWidgetDragger; class RiuDraggableOverlayFrame : public QFrame { Q_OBJECT public: - RiuDraggableOverlayFrame( QWidget* parent, - QWidget* widgetToSnapTo = nullptr, - const QColor& backgroundColor = QColor( 255, 255, 255, 100 ) ); - QLabel* label(); + enum class AnchorCorner + { + TopLeft, + TopRight, + }; -protected: - QPointer m_overlayItemLabel; +public: + RiuDraggableOverlayFrame( QWidget* parent, + const int snapMargins, + const QColor& backgroundColor = QColor( 255, 255, 255, 100 ) ); + + RiuAbstractOverlayContentFrame* contentFrame(); + void setContentFrame( RiuAbstractOverlayContentFrame* contentFrame ); + void renderTo( QPainter* painter, const QRect& targetRect ); + + void setAnchorCorner( AnchorCorner corner ); + AnchorCorner anchorCorner() const; + + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + +private: + QPointer m_widgetDragger; + QPointer m_layout; + QPointer m_contentFrame; + AnchorCorner m_anchorCorner; }; diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp index 819295b17b..7f71489387 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp @@ -85,9 +85,7 @@ RiuGridCrossQwtPlot::RiuGridCrossQwtPlot( RimPlot* plotDefinition, QWidget* pare connect( m_zoomerRight, SIGNAL( zoomed( const QRectF& ) ), SLOT( onZoomedSlot() ) ); connect( panner, SIGNAL( panned( int, int ) ), SLOT( onZoomedSlot() ) ); - m_annotationTool = std::unique_ptr( new RiuPlotAnnotationTool() ); - m_infoBox = new RiuDraggableOverlayFrame( this, canvas() ); - + m_annotationTool = std::unique_ptr( new RiuPlotAnnotationTool() ); m_selectedPointMarker = new QwtPlotMarker; // QwtPlotMarker takes ownership of the symbol, it is deleted in destructor of QwtPlotMarker @@ -121,112 +119,6 @@ RiuGridCrossQwtPlot::~RiuGridCrossQwtPlot() delete m_selectedPointMarker; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::addOrUpdateDataSetLegend( RimGridCrossPlotDataSet* dataSet ) -{ - RiuCvfOverlayItemWidget* overlayWidget = nullptr; - - auto it = m_legendWidgets.find( dataSet ); - if ( it == m_legendWidgets.end() || it->second == nullptr ) - { - overlayWidget = new RiuCvfOverlayItemWidget( this, canvas() ); - m_legendWidgets[dataSet] = overlayWidget; - } - else - { - overlayWidget = it->second; - } - - if ( overlayWidget ) - { - caf::TitledOverlayFrame* overlayItem = dataSet->legendConfig()->titledOverlayFrame(); - applyFontSizeToOverlayItem( overlayItem ); - resizeOverlayItemToFitPlot( overlayItem ); - overlayWidget->updateFromOverlayItem( overlayItem ); - } - this->updateLegendLayout(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::removeDataSetLegend( RimGridCrossPlotDataSet* dataSetToShowLegendFor ) -{ - auto it = m_legendWidgets.find( dataSetToShowLegendFor ); - if ( it != m_legendWidgets.end() ) - { - if ( it->second != nullptr ) - { - it->second->hide(); - it->second->setParent( nullptr ); - delete it->second; - } - - m_legendWidgets.erase( it ); - } - - this->updateLegendLayout(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::removeDanglingDataSetLegends() -{ - for ( auto it = m_legendWidgets.begin(); it != m_legendWidgets.end(); ) - { - if ( it->first.isNull() ) - { - if ( it->second != nullptr ) - { - it->second->hide(); - it->second->setParent( nullptr ); - delete it->second; - } - m_legendWidgets.erase( it++ ); - } - else - { - ++it; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::updateLegendSizesToMatchPlot() -{ - RimGridCrossPlot* crossPlot = dynamic_cast( plotDefinition() ); - if ( !crossPlot ) return; - - bool anyLegendResized = false; - - for ( RimGridCrossPlotDataSet* dataSet : crossPlot->dataSets() ) - { - if ( !dataSet->isChecked() || !dataSet->legendConfig()->showLegend() ) continue; - - auto pairIt = m_legendWidgets.find( dataSet ); - if ( pairIt != m_legendWidgets.end() ) - { - RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; - caf::TitledOverlayFrame* overlayItem = dataSet->legendConfig()->titledOverlayFrame(); - applyFontSizeToOverlayItem( overlayItem ); - if ( resizeOverlayItemToFitPlot( overlayItem ) ) - { - anyLegendResized = true; - overlayWidget->updateFromOverlayItem( overlayItem ); - } - } - } - if ( anyLegendResized ) - { - updateLegendLayout(); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -265,11 +157,10 @@ void RiuGridCrossQwtPlot::setLegendFontSize( int fontSize ) label->setFont( font ); } } - updateInfoBoxLayout(); } //-------------------------------------------------------------------------------------------------- -/// The internal qwt legend is not used in grid plot windows +/// The internal qwt legend is not used in multi plot windows //-------------------------------------------------------------------------------------------------- void RiuGridCrossQwtPlot::setInternalQwtLegendVisible( bool visible ) { @@ -283,169 +174,6 @@ void RiuGridCrossQwtPlot::setInternalQwtLegendVisible( bool visible ) this->insertLegend( nullptr ); } } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::updateLayout() -{ - QwtPlot::updateLayout(); - updateInfoBoxLayout(); - updateLegendLayout(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::updateInfoBoxLayout() -{ - RimGridCrossPlot* crossPlot = dynamic_cast( plotDefinition() ); - if ( !crossPlot ) return; - - bool showInfo = false; - if ( crossPlot->showInfoBox() ) - { - QStringList curveInfoTexts; - for ( auto dataSet : crossPlot->dataSets() ) - { - QString curveInfoText = dataSet->infoText(); - if ( dataSet->isChecked() && !curveInfoText.isEmpty() ) - { - curveInfoTexts += curveInfoText; - } - } - QStringList infoText; - infoText << QString( "View ID: %1
" ).arg( crossPlot->id() ); - if ( curveInfoTexts.size() > 1 ) - { - infoText += QString( "
    " ); - for ( QString curveInfoText : curveInfoTexts ) - { - infoText += QString( "
  1. %1
  2. " ).arg( curveInfoText ); - } - infoText += QString( "
" ); - } - else if ( curveInfoTexts.size() > 0 ) - { - infoText += curveInfoTexts.front(); - } - if ( !infoText.empty() ) - { - m_infoBox->label()->setText( infoText.join( "\n" ) ); - QFont font = m_infoBox->label()->font(); - font.setPointSize( crossPlot->legendFontSize() ); - m_infoBox->label()->setFont( font ); - m_infoBox->adjustSize(); - QRect infoRect = m_infoBox->frameGeometry(); - QRect canvasRect = canvas()->frameGeometry(); - infoRect.moveTop( canvasRect.top() + 4 ); - infoRect.moveRight( canvasRect.right() - 4 ); - m_infoBox->move( infoRect.topLeft() ); - showInfo = true; - } - } - if ( showInfo ) - { - m_infoBox->show(); - } - else - { - m_infoBox->hide(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::updateLegendLayout() -{ - const int spacing = 5; - int startMarginX = this->canvas()->pos().x() + spacing; - int startMarginY = this->canvas()->pos().y() + spacing; - - int xpos = startMarginX; - int ypos = startMarginY; - int maxColumnWidth = 0; - - removeDanglingDataSetLegends(); - - RimGridCrossPlot* crossPlot = dynamic_cast( plotDefinition() ); - - if ( !crossPlot ) return; - - std::set legendTypes; - - for ( RimGridCrossPlotDataSet* dataSet : crossPlot->dataSets() ) - { - if ( dataSet->isChecked() && dataSet->groupingEnabled() && dataSet->legendConfig()->showLegend() ) - { - auto pairIt = m_legendWidgets.find( dataSet ); - if ( pairIt != m_legendWidgets.end() ) - { - RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; - - // Show only one copy of each legend type - if ( !legendTypes.count( dataSet->groupParameter() ) ) - { - if ( ypos + overlayWidget->height() + spacing > this->canvas()->height() ) - { - xpos += spacing + maxColumnWidth; - ypos = startMarginY; - maxColumnWidth = 0; - } - - overlayWidget->show(); - overlayWidget->move( xpos, ypos ); - - ypos += pairIt->second->height() + spacing; - maxColumnWidth = std::max( maxColumnWidth, pairIt->second->width() ); - legendTypes.insert( dataSet->groupParameter() ); - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::resizeEvent( QResizeEvent* e ) -{ - QwtPlot::resizeEvent( e ); - updateLegendSizesToMatchPlot(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RiuGridCrossQwtPlot::resizeOverlayItemToFitPlot( caf::TitledOverlayFrame* overlayItem ) -{ - QSize plotSize = this->canvas()->contentsRect().size(); - cvf::Vec2ui existingRenderSize = overlayItem->renderSize(); - cvf::Vec2ui legendSize = overlayItem->preferredSize(); - - bool sizeAltered = false; - - if ( plotSize.width() > 0 && (double)legendSize.x() > 0.9 * plotSize.width() ) - { - legendSize.x() = ( plotSize.width() * 9 ) / 10; - sizeAltered = true; - } - if ( plotSize.height() > 0 && (double)legendSize.y() > 0.9 * plotSize.height() ) - { - legendSize.y() = ( plotSize.height() * 9 ) / 10; - sizeAltered = true; - } - overlayItem->setRenderSize( legendSize ); - - if ( legendSize.x() != existingRenderSize.x() || legendSize.y() != existingRenderSize.y() ) - { - sizeAltered = true; - } - - return sizeAltered; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -531,17 +259,6 @@ bool RiuGridCrossQwtPlot::curveText( const QwtPlotCurve* curve, return false; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuGridCrossQwtPlot::applyFontSizeToOverlayItem( caf::TitledOverlayFrame* overlayItem ) -{ - RimGridCrossPlot* crossPlot = static_cast( ownerViewWindow() ); - int fontSize = crossPlot->legendFontSize(); - cvf::ref cafFont = RiaFontCache::getFont( RiaFontCache::fontSizeEnumFromPointSize( fontSize ) ); - overlayItem->setFont( cafFont.p() ); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h index f8c7ce5c1f..dd2927997f 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h @@ -55,10 +55,6 @@ public: RiuGridCrossQwtPlot( const RiuGridCrossQwtPlot& ) = delete; - void addOrUpdateDataSetLegend( RimGridCrossPlotDataSet* dataSetToShowLegendFor ); - void removeDataSetLegend( RimGridCrossPlotDataSet* dataSetToShowLegendFor ); - void removeDanglingDataSetLegends(); - void updateLegendSizesToMatchPlot(); void updateAnnotationObjects( RimPlotAxisProperties* axisProperties ); RimViewWindow* ownerViewWindow() const override; @@ -67,17 +63,11 @@ public: void setInternalQwtLegendVisible( bool visible ); protected: - void updateLayout() override; - void updateInfoBoxLayout(); - void updateLegendLayout(); - void resizeEvent( QResizeEvent* e ) override; - bool resizeOverlayItemToFitPlot( caf::TitledOverlayFrame* overlayItem ); void contextMenuEvent( QContextMenuEvent* ) override; void selectPoint( QwtPlotCurve* curve, int pointNumber ) override; void clearPointSelection() override; bool curveText( const QwtPlotCurve* curve, QString* curveTitle, QString* xParamName, QString* yParamName ) const; - void applyFontSizeToOverlayItem( caf::TitledOverlayFrame* overlayItem ); bool isZoomerActive() const override; void endZoomOperations() override; @@ -85,12 +75,6 @@ private slots: void onZoomedSlot(); private: - typedef caf::PdmPointer DataSetPtr; - typedef QPointer LegendPtr; - typedef QPointer InfoBoxPtr; - - InfoBoxPtr m_infoBox; - std::map m_legendWidgets; std::unique_ptr m_annotationTool; QwtPlotMarker* m_selectedPointMarker; diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index c5155869ce..a780622f1a 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -680,7 +680,6 @@ void RiuMainWindow::createDockPanels() m_projectTreeView = new caf::PdmUiTreeView( this ); m_projectTreeView->enableSelectionManagerUpdating( true ); - m_styleSheet.applyToWidgetAndChildren( m_projectTreeView ); RiaApplication* app = RiaApplication::instance(); m_projectTreeView->enableAppendOfClassNameToUiItemText( app->preferences()->appendClassNameToUiText() ); diff --git a/ApplicationCode/UserInterface/RiuMainWindowBase.cpp b/ApplicationCode/UserInterface/RiuMainWindowBase.cpp index 8beec1f2eb..21c00c655d 100644 --- a/ApplicationCode/UserInterface/RiuMainWindowBase.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindowBase.cpp @@ -46,7 +46,6 @@ RiuMainWindowBase::RiuMainWindowBase() , m_blockSubWindowProjectTreeSelection( false ) { setDockNestingEnabled( true ); - m_styleSheet = createStyleSheet(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuMainWindowBase.h b/ApplicationCode/UserInterface/RiuMainWindowBase.h index 4c4d45ed7c..2907abe6a6 100644 --- a/ApplicationCode/UserInterface/RiuMainWindowBase.h +++ b/ApplicationCode/UserInterface/RiuMainWindowBase.h @@ -94,7 +94,6 @@ protected slots: protected: caf::PdmUiTreeView* m_projectTreeView; - caf::UiStyleSheet m_styleSheet; bool m_allowActiveViewChangeFromSelection; // To be used in selectedObjectsChanged() to control // whether to select the corresponding active view or not private: diff --git a/ApplicationCode/UserInterface/RiuMultiPlotWindow.cpp b/ApplicationCode/UserInterface/RiuMultiPlotWindow.cpp index 2d41c43fbd..ce33cb6ba2 100644 --- a/ApplicationCode/UserInterface/RiuMultiPlotWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMultiPlotWindow.cpp @@ -42,10 +42,12 @@ #include "qwt_legend.h" #include "qwt_plot_layout.h" +#include "qwt_plot_renderer.h" #include "qwt_scale_draw.h" #include #include +#include #include #include #include @@ -279,6 +281,14 @@ void RiuMultiPlotWindow::scheduleReplotOfAllPlots() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMultiPlotWindow::renderTo( QPainter* painter ) +{ + doRenderTo( painter ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -437,7 +447,7 @@ void RiuMultiPlotWindow::dropEvent( QDropEvent* event ) if ( insertAfter != plotToMove ) { - m_plotDefinition->movePlotsToThis( { plotToMove }, insertAfter ); + m_plotDefinition->movePlotsToThis( {plotToMove}, insertAfter ); } } } @@ -534,13 +544,22 @@ void RiuMultiPlotWindow::reinsertPlotWidgets() for ( int tIdx = 0; tIdx < m_plotWidgets.size(); ++tIdx ) { - m_plotWidgets[tIdx]->hide(); - m_legends[tIdx]->hide(); - m_subTitles[tIdx]->hide(); + if ( m_plotWidgets[tIdx] ) + { + m_plotWidgets[tIdx]->hide(); + } + if ( m_legends[tIdx] ) + { + m_legends[tIdx]->hide(); + } + if ( m_subTitles[tIdx] ) + { + m_subTitles[tIdx]->hide(); + } } - QList> subTitles = this->visibleTitles(); - QList> legends = this->visibleLegends(); + QList> subTitles = this->subTitlesForVisiblePlots(); + QList> legends = this->legendsForVisiblePlots(); QList> plotWidgets = this->visiblePlotWidgets(); if ( plotWidgets.empty() && acceptDrops() ) @@ -566,7 +585,8 @@ void RiuMultiPlotWindow::reinsertPlotWidgets() std::tie( row, column ) = findAvailableRowAndColumn( row, column, colSpan, rowAndColumnCount.second ); m_gridLayout->addWidget( subTitles[visibleIndex], 3 * row, column, 1, colSpan ); - m_gridLayout->addWidget( legends[visibleIndex], 3 * row + 1, column, 1, colSpan ); + m_gridLayout + ->addWidget( legends[visibleIndex], 3 * row + 1, column, 1, colSpan, Qt::AlignHCenter | Qt::AlignBottom ); m_gridLayout->addWidget( plotWidgets[visibleIndex], 3 * row + 2, column, 1 + ( rowSpan - 1 ) * 3, colSpan ); subTitles[visibleIndex]->setVisible( m_plotDefinition->showPlotTitles() ); @@ -617,7 +637,7 @@ int RiuMultiPlotWindow::alignCanvasTops() CVF_ASSERT( m_legends.size() == m_plotWidgets.size() ); QList> plotWidgets = visiblePlotWidgets(); - QList> legends = visibleLegends(); + QList> legends = legendsForVisiblePlots(); if ( plotWidgets.empty() ) return 0; auto rowAndColumnCount = this->rowAndColumnCount( plotWidgets.size() ); @@ -701,7 +721,7 @@ QList> RiuMultiPlotWindow::visiblePlotWidgets() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QList> RiuMultiPlotWindow::visibleLegends() const +QList> RiuMultiPlotWindow::legendsForVisiblePlots() const { QList> legends; for ( int i = 0; i < m_plotWidgets.size(); ++i ) @@ -717,7 +737,7 @@ QList> RiuMultiPlotWindow::visibleLegends() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QList> RiuMultiPlotWindow::visibleTitles() const +QList> RiuMultiPlotWindow::subTitlesForVisiblePlots() const { QList> subTitles; for ( int i = 0; i < m_plotWidgets.size(); ++i ) @@ -765,3 +785,37 @@ std::pair } return std::make_pair( availableRow, availableColumn ); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMultiPlotWindow::doRenderTo( QPainter* painter ) +{ + setSelectionsVisible( false ); + m_plotTitle->render( painter ); + + for ( auto subTitle : subTitlesForVisiblePlots() ) + { + if ( subTitle->isVisible() ) + { + subTitle->render( painter, m_plotWidgetFrame->mapToParent( subTitle->frameGeometry().topLeft() ) ); + } + } + + for ( auto legend : legendsForVisiblePlots() ) + { + legend->render( painter, m_plotWidgetFrame->mapToParent( legend->frameGeometry().topLeft() ) ); + } + + for ( auto plotWidget : visiblePlotWidgets() ) + { + QRect plotWidgetGeometry = plotWidget->frameGeometry(); + QPoint plotWidgetTopLeft = plotWidgetGeometry.topLeft(); + QPoint plotWidgetFrameTopLeft = m_plotWidgetFrame->frameGeometry().topLeft(); + plotWidgetGeometry.moveTo( plotWidgetTopLeft + plotWidgetFrameTopLeft ); + + plotWidget->renderTo( painter, plotWidgetGeometry ); + } + + setSelectionsVisible( true ); +} diff --git a/ApplicationCode/UserInterface/RiuMultiPlotWindow.h b/ApplicationCode/UserInterface/RiuMultiPlotWindow.h index 73fa01d0ce..dcba811dca 100644 --- a/ApplicationCode/UserInterface/RiuMultiPlotWindow.h +++ b/ApplicationCode/UserInterface/RiuMultiPlotWindow.h @@ -41,8 +41,11 @@ class RiuQwtPlotWidget; class QFocusEvent; class QLabel; +class QPainter; class QScrollBar; +class QwtLegend; class QwtLegendData; +class QwtPlot; //================================================================================================== // @@ -78,6 +81,8 @@ public: void scheduleReplotOfAllPlots(); virtual void updateVerticalScrollBar( double visibleMin, double visibleMax, double totalMin, double totalMax ) {} + void renderTo( QPainter* painter ); + protected: void contextMenuEvent( QContextMenuEvent* ) override; QLabel* createTitleLabel() const; @@ -104,11 +109,13 @@ protected: caf::UiStyleSheet createDropTargetStyleSheet(); QList> visiblePlotWidgets() const; - QList> visibleLegends() const; - QList> visibleTitles() const; + QList> legendsForVisiblePlots() const; + QList> subTitlesForVisiblePlots() const; std::pair findAvailableRowAndColumn( int startRow, int startColumn, int columnSpan, int columnCount ) const; + virtual void doRenderTo( QPainter* painter ); + private slots: virtual void performUpdate(); void onLegendUpdated(); diff --git a/ApplicationCode/UserInterface/RiuQwtPlotLegend.cpp b/ApplicationCode/UserInterface/RiuQwtPlotLegend.cpp index 04ef9b9020..2a8b0c3439 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotLegend.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotLegend.cpp @@ -31,6 +31,11 @@ RiuQwtPlotLegend::RiuQwtPlotLegend( QWidget* parent /*= nullptr */ ) : QwtLegend( parent ) , m_columnCount( 1 ) { + QwtDynGridLayout* legendLayout = qobject_cast( contentsWidget()->layout() ); + if ( legendLayout ) + { + legendLayout->setExpandingDirections( Qt::Horizontal | Qt::Vertical ); + } } //-------------------------------------------------------------------------------------------------- @@ -75,7 +80,7 @@ QSize RiuQwtPlotLegend::sizeHint() const maxHeight = std::max( maxHeight, itemSize.height() ); } QMargins margins = legendLayout->contentsMargins(); - int totalSpacing = ( numRows + 1 ) * legendLayout->spacing() + margins.top() + margins.bottom(); + int totalSpacing = ( numRows + 2 ) * legendLayout->spacing() + margins.top() + margins.bottom(); int height = maxHeight * numRows + totalSpacing; diff --git a/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp b/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp index cddac8a637..be06df9c1e 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp @@ -119,8 +119,6 @@ void RiuQwtPlotTools::setDefaultAxes( QwtPlot* plot ) plot->enableAxis( QwtPlot::xTop, false ); plot->enableAxis( QwtPlot::yRight, false ); - plot->axisScaleDraw( QwtPlot::xBottom )->enableComponent( QwtAbstractScaleDraw::Backbone, false ); - plot->axisScaleDraw( QwtPlot::yLeft )->enableComponent( QwtAbstractScaleDraw::Backbone, false ); plot->axisWidget( QwtPlot::xBottom )->setMargin( 0 ); plot->axisWidget( QwtPlot::yLeft )->setMargin( 0 ); diff --git a/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp b/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp index d78f9b77aa..7e5bd5e900 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotWidget.cpp @@ -21,11 +21,13 @@ #include "RiaApplication.h" #include "RiaColorTools.h" +#include "RiaFontCache.h" #include "RiaPlotWindowRedrawScheduler.h" #include "RimPlot.h" #include "RimPlotCurve.h" +#include "RiuDraggableOverlayFrame.h" #include "RiuPlotMainWindowTools.h" #include "RiuQwtCurvePointTracker.h" #include "RiuQwtLinearScaleEngine.h" @@ -35,16 +37,19 @@ #include "cafAssert.h" #include "qwt_legend.h" +#include "qwt_plot_canvas.h" #include "qwt_plot_curve.h" #include "qwt_plot_grid.h" #include "qwt_plot_layout.h" #include "qwt_plot_marker.h" #include "qwt_plot_picker.h" +#include "qwt_plot_renderer.h" #include "qwt_scale_draw.h" #include "qwt_scale_widget.h" #include "qwt_symbol.h" #include "qwt_text.h" +#include #include #include #include @@ -55,6 +60,7 @@ #include #include +#include #include //-------------------------------------------------------------------------------------------------- @@ -64,6 +70,7 @@ RiuQwtPlotWidget::RiuQwtPlotWidget( RimPlot* plot, QWidget* parent ) : QwtPlot( parent ) , m_plotDefinition( plot ) , m_draggable( true ) + , m_overlayMargins( 5 ) { RiuQwtPlotTools::setCommonPlotBehaviour( this ); @@ -404,11 +411,11 @@ void RiuQwtPlotWidget::setWidgetState( const QString& widgetState ) //-------------------------------------------------------------------------------------------------- /// Adds an overlay frame. The overlay frame becomes the responsibility of the plot widget //-------------------------------------------------------------------------------------------------- -void RiuQwtPlotWidget::addOverlayFrame( QFrame* overlayFrame ) +void RiuQwtPlotWidget::addOverlayFrame( RiuDraggableOverlayFrame* overlayFrame ) { if ( std::find( m_overlayFrames.begin(), m_overlayFrames.end(), overlayFrame ) == m_overlayFrames.end() ) { - overlayFrame->setParent( this ); + overlayFrame->setParent( this->canvas() ); m_overlayFrames.push_back( overlayFrame ); updateLayout(); } @@ -417,7 +424,7 @@ void RiuQwtPlotWidget::addOverlayFrame( QFrame* overlayFrame ) //-------------------------------------------------------------------------------------------------- /// Remove the overlay widget. The frame becomes the responsibility of the caller //-------------------------------------------------------------------------------------------------- -void RiuQwtPlotWidget::removeOverlayFrame( QFrame* overlayFrame ) +void RiuQwtPlotWidget::removeOverlayFrame( RiuDraggableOverlayFrame* overlayFrame ) { overlayFrame->hide(); overlayFrame->setParent( nullptr ); @@ -544,6 +551,16 @@ void RiuQwtPlotWidget::showEvent( QShowEvent* event ) QwtPlot::showEvent( event ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::resizeEvent( QResizeEvent* event ) +{ + QwtPlot::resizeEvent( event ); + updateOverlayFrameLayout(); + event->accept(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -587,6 +604,47 @@ bool RiuQwtPlotWidget::isZoomerActive() const //-------------------------------------------------------------------------------------------------- void RiuQwtPlotWidget::endZoomOperations() {} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::renderTo( QPainter* painter, const QRect& targetRect ) +{ + static_cast( this->canvas() )->setPaintAttribute( QwtPlotCanvas::BackingStore, false ); + QwtPlotRenderer renderer( this ); + renderer.render( this, painter, targetRect ); + static_cast( this->canvas() )->setPaintAttribute( QwtPlotCanvas::BackingStore, true ); + + for ( RiuDraggableOverlayFrame* overlayFrame : m_overlayFrames ) + { + if ( overlayFrame->isVisible() ) + { + QPoint overlayTopLeftInCanvasCoords = overlayFrame->frameGeometry().topLeft(); + QPoint canvasTopLeftInPlotCoords = this->canvas()->frameGeometry().topLeft(); + QPoint plotTopLeftInWindowCoords = targetRect.topLeft(); + + QPoint overlayTopLeftInWindowCoords = plotTopLeftInWindowCoords + canvasTopLeftInPlotCoords + + overlayTopLeftInCanvasCoords; + { + QRect overlayRect = overlayFrame->frameGeometry(); + QSize desiredSize = overlayRect.size(); + QSize minimumSize = overlayFrame->minimumSizeHint(); + QSize actualSize = desiredSize.expandedTo( minimumSize ); + overlayRect.moveTo( overlayTopLeftInWindowCoords ); + overlayRect.setSize( actualSize ); + overlayFrame->renderTo( painter, overlayRect ); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuQwtPlotWidget::overlayMargins() const +{ + return m_overlayMargins; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -651,26 +709,47 @@ caf::UiStyleSheet RiuQwtPlotWidget::createCanvasStyleSheet() const //-------------------------------------------------------------------------------------------------- void RiuQwtPlotWidget::updateOverlayFrameLayout() { - const int spacing = 5; - int startMarginX = this->canvas()->pos().x() + spacing; - int startMarginY = this->canvas()->pos().y() + spacing; + const int spacing = 5; - int xpos = startMarginX; - int ypos = startMarginY; - int maxColumnWidth = 0; - for ( QPointer frame : m_overlayFrames ) + int xpos = spacing; + int ypos = spacing; + int widthOfCurrentColumn = 0; + + QSize canvasSize = this->canvas()->size(); + QSize maxFrameSize( canvasSize.width() - 2 * m_overlayMargins, canvasSize.height() - 2 * m_overlayMargins ); + + for ( RiuDraggableOverlayFrame* frame : m_overlayFrames ) { - if ( !frame.isNull() ) + if ( frame ) { - if ( ypos + frame->height() + spacing > this->canvas()->height() ) + QSize minFrameSize = frame->minimumSizeHint(); + QSize desiredFrameSize = frame->sizeHint(); + + int width = std::min( std::max( minFrameSize.width(), desiredFrameSize.width() ), maxFrameSize.width() ); + int height = std::min( std::max( minFrameSize.height(), desiredFrameSize.height() ), maxFrameSize.height() ); + + frame->resize( width, height ); + + if ( frame->anchorCorner() == RiuDraggableOverlayFrame::AnchorCorner::TopLeft ) { - xpos += spacing + maxColumnWidth; - ypos = startMarginY; - maxColumnWidth = 0; + if ( ypos + frame->height() + spacing > this->canvas()->height() && widthOfCurrentColumn > 0 ) + { + xpos += spacing + widthOfCurrentColumn; + ypos = spacing; + widthOfCurrentColumn = 0; + } + frame->move( xpos, ypos ); + ypos += frame->height() + spacing; + widthOfCurrentColumn = std::max( widthOfCurrentColumn, frame->width() ); + } + else if ( frame->anchorCorner() == RiuDraggableOverlayFrame::AnchorCorner::TopRight ) + { + QRect frameRect = frame->frameGeometry(); + QRect canvasRect = canvas()->rect(); + QPoint canvasTopRight = canvasRect.topRight(); + frameRect.moveTopRight( QPoint( canvasTopRight.x() - spacing, canvasTopRight.y() + spacing ) ); + frame->move( frameRect.topLeft() ); } - frame->move( xpos, ypos ); - ypos += frame->height() + spacing; - maxColumnWidth = std::max( maxColumnWidth, frame->width() ); frame->show(); } } diff --git a/ApplicationCode/UserInterface/RiuQwtPlotWidget.h b/ApplicationCode/UserInterface/RiuQwtPlotWidget.h index 55b246a549..31037b60f4 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotWidget.h +++ b/ApplicationCode/UserInterface/RiuQwtPlotWidget.h @@ -32,6 +32,7 @@ class RiaPlotWindowRedrawScheduler; class RimPlot; +class RiuDraggableOverlayFrame; class QwtLegend; class QwtPicker; @@ -98,16 +99,20 @@ public: void scheduleReplot(); void setWidgetState( const QString& widgetState ); - void addOverlayFrame( QFrame* overlayWidget ); - void removeOverlayFrame( QFrame* overlayWidget ); + void addOverlayFrame( RiuDraggableOverlayFrame* overlayWidget ); + void removeOverlayFrame( RiuDraggableOverlayFrame* overlayWidget ); void updateLayout() override; + void renderTo( QPainter* painter, const QRect& targetRect ); + int overlayMargins() const; + protected: QSize sizeHint() const override; QSize minimumSizeHint() const override; bool eventFilter( QObject* watched, QEvent* event ) override; void hideEvent( QHideEvent* event ) override; void showEvent( QShowEvent* event ) override; + void resizeEvent( QResizeEvent* event ) override; void applyAxisTitleToQwt( QwtPlot::Axis axis ); @@ -138,8 +143,9 @@ private: std::map m_axisTitlesEnabled; QPointer m_plotPicker; bool m_draggable; + const int m_overlayMargins; - QList> m_overlayFrames; + QList> m_overlayFrames; struct CurveColors { diff --git a/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.cpp b/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.cpp new file mode 100644 index 0000000000..01b2185bba --- /dev/null +++ b/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.cpp @@ -0,0 +1,203 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RiuScalarMapperLegendFrame.h" + +#include "cvfString.h" +#include "cvfqtUtils.h" + +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuScalarMapperLegendFrame::RiuScalarMapperLegendFrame( QWidget* parent, + const QString& title, + cvf::ScalarMapper* scalarMapper ) + : RiuAbstractLegendFrame( parent, title ) + , m_scalarMapper( scalarMapper ) + , m_tickNumberPrecision( 4 ) + , m_numberFormat( RimRegularLegendConfig::AUTO ) +{ + if ( m_scalarMapper.notNull() ) + { + m_scalarMapper->majorTickValues( &m_tickValues ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuScalarMapperLegendFrame::~RiuScalarMapperLegendFrame() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuScalarMapperLegendFrame::setTickPrecision( int precision ) +{ + m_tickNumberPrecision = precision; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuScalarMapperLegendFrame::setTickFormat( NumberFormat format ) +{ + m_numberFormat = format; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuScalarMapperLegendFrame::layoutInfo( LayoutInfo* layout ) const +{ + QFontMetrics fontMetrics( this->font() ); + QStringList titleLines = m_title.split( "\n", QString::SkipEmptyParts ); + + layout->charHeight = fontMetrics.height(); + layout->charAscent = fontMetrics.ascent(); + layout->lineSpacing = ( fontMetrics.lineSpacing() * 3 ) / 2; + layout->margins = QMargins( 8, 8, 8, 8 ); + layout->tickTextLeadSpace = 5; + + int colorBarWidth = 25; + int colorBarHeight = layout->overallLegendSize.height() - layout->margins.top() - layout->margins.bottom() - + titleLines.size() * layout->lineSpacing; + + int colorBarStartY = layout->margins.top() + titleLines.size() * layout->lineSpacing; + + layout->colorBarRect = QRect( layout->margins.left(), colorBarStartY, colorBarWidth, colorBarHeight ); + + layout->tickStartX = layout->margins.left(); + layout->tickMidX = layout->margins.left() + layout->colorBarRect.width(); + layout->tickEndX = layout->tickMidX + 5; + + // Build array containing the pixel positions of all the ticks + int numTicks = (int)m_tickValues.size(); + layout->tickYPixelPos.reserve( numTicks ); + + int i; + for ( i = 0; i < numTicks; i++ ) + { + double t = 0.0; + if ( m_scalarMapper.notNull() ) + { + t = cvf::Math::clamp( m_scalarMapper->normalizedValue( m_tickValues[i] ), 0.0, 1.1 ); + } + + if ( i == 0 ) + { + layout->tickYPixelPos.push_back( 0.0 ); + } + else if ( i == numTicks - 1 ) + { + layout->tickYPixelPos.push_back( layout->colorBarRect.height() ); + } + else + { + layout->tickYPixelPos.push_back( t * layout->colorBarRect.height() ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiuScalarMapperLegendFrame::label( int index ) const +{ + double tickValue = m_tickValues[index]; + QString valueString; + switch ( m_numberFormat ) + { + case RimRegularLegendConfig::FIXED: + valueString = QString::number( tickValue, 'f', m_tickNumberPrecision ); + break; + case RimRegularLegendConfig::SCIENTIFIC: + valueString = QString::number( tickValue, 'e', m_tickNumberPrecision ); + break; + default: + valueString = QString::number( tickValue ); + break; + } + return valueString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuScalarMapperLegendFrame::labelCount() const +{ + return (int)m_tickValues.size(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuScalarMapperLegendFrame::rectCount() const +{ + return (int)m_tickValues.size() - 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuScalarMapperLegendFrame::renderRect( QPainter* painter, const LayoutInfo& layout, int rectIndex ) const +{ + int rectIndexFromBottom = rectCount() - rectIndex - 1; + cvf::Color3ub startColor = m_scalarMapper->mapToColor( + m_scalarMapper->domainValue( m_tickValues[rectIndexFromBottom] ) ); + cvf::Color3ub endColor = m_scalarMapper->mapToColor( + m_scalarMapper->domainValue( m_tickValues[rectIndexFromBottom + 1] ) ); + QColor startQColor( startColor.r(), startColor.g(), startColor.b() ); + QColor endQColor( endColor.r(), endColor.g(), endColor.b() ); + + QRectF gradientRect( QPointF( layout.tickStartX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), + QPointF( layout.tickStartX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); + + QLinearGradient gradient( gradientRect.topLeft(), gradientRect.bottomRight() ); + gradient.setCoordinateMode( QGradient::LogicalMode ); + gradient.setColorAt( 0.0, startQColor ); + gradient.setColorAt( 1.0, endQColor ); + + QRectF rect( QPointF( layout.tickStartX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), + QPointF( layout.tickMidX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); + + painter->fillRect( rect, QBrush( gradient ) ); + painter->drawLine( QPointF( layout.tickStartX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ), + QPointF( layout.tickEndX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom] + 1 ) ); + painter->drawLine( QPointF( layout.tickStartX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ), + QPointF( layout.tickEndX, + layout.colorBarRect.bottom() - layout.tickYPixelPos[rectIndexFromBottom + 1] + 1 ) ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuScalarMapperLegendFrame::labelPixelPosY( const LayoutInfo& layout, int index ) const +{ + int indexFromBottom = labelCount() - index - 1; + return layout.colorBarRect.bottom() - layout.tickYPixelPos[indexFromBottom] + layout.charAscent / 2; +} diff --git a/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.h b/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.h new file mode 100644 index 0000000000..cb1d0492c3 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuScalarMapperLegendFrame.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor 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 "RimRegularLegendConfig.h" +#include "RiuAbstractLegendFrame.h" + +#include "cvfObject.h" +#include "cvfRect.h" +#include "cvfScalarMapper.h" + +#include +#include + +class QFont; +class QPaintEvent; +class QPainter; +class QRect; + +class RiuScalarMapperLegendFrame : public RiuAbstractLegendFrame +{ + Q_OBJECT + +public: + using NumberFormat = RimRegularLegendConfig::NumberFormatType; + +public: + RiuScalarMapperLegendFrame( QWidget* parent, const QString& title, cvf::ScalarMapper* scalarMapper ); + ~RiuScalarMapperLegendFrame(); + + void setTickPrecision( int precision ); + void setTickFormat( NumberFormat format ); + +private: + void layoutInfo( LayoutInfo* layout ) const override; + QString label( int index ) const override; + int labelCount() const override; + int rectCount() const override; + void renderRect( QPainter* painter, const LayoutInfo& layout, int rectIndex ) const override; + int labelPixelPosY( const LayoutInfo& layout, int index ) const override; + +private: + cvf::cref m_scalarMapper; + std::vector m_tickValues; + int m_tickNumberPrecision; + NumberFormat m_numberFormat; +}; diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index c73e375277..55534c12b8 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -27,14 +27,6 @@ RiuWellLogPlot::RiuWellLogPlot( RimWellLogPlot* plotDefinition, QWidget* parent connect( m_trackScrollBar, SIGNAL( valueChanged( int ) ), this, SLOT( slotSetMinDepth( int ) ) ); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RiuWellLogPlot::isScrollbarVisible() const -{ - return m_trackScrollBar->isVisible(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -48,9 +40,11 @@ RimWellLogPlot* RiuWellLogPlot::wellLogPlotDefinition() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuWellLogPlot::setScrollbarVisible( bool visible ) +void RiuWellLogPlot::doRenderTo( QPainter* painter ) { - m_trackScrollBar->setVisible( visible ); + m_trackScrollBar->setVisible( false ); + RiuMultiPlotWindow::doRenderTo( painter ); + m_trackScrollBar->setVisible( true ); } //-------------------------------------------------------------------------------------------------- @@ -102,7 +96,7 @@ bool RiuWellLogPlot::showYAxis( int row, int column ) const void RiuWellLogPlot::reinsertScrollbar() { QList> plotWidgets = this->visiblePlotWidgets(); - QList> legends = this->visibleLegends(); + QList> legends = this->legendsForVisiblePlots(); int rowCount = this->m_gridLayout->rowCount(); int colCount = this->m_gridLayout->columnCount(); diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.h b/ApplicationCode/UserInterface/RiuWellLogPlot.h index 2f08b09f9a..ff52d87d32 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.h +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.h @@ -28,8 +28,6 @@ class RiuWellLogPlot : public RiuMultiPlotWindow public: RiuWellLogPlot( RimWellLogPlot* plotDefinition, QWidget* parent ); - bool isScrollbarVisible() const; - void setScrollbarVisible( bool visible ); void updateVerticalScrollBar( double minVisible, double maxVisible, double minAvailable, double maxAvailable ) override; protected: @@ -39,6 +37,7 @@ protected: void reinsertScrollbar(); void alignScrollbar( int offset ); + void doRenderTo( QPainter* painter ) override; private: RimWellLogPlot* wellLogPlotDefinition(); diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp index 38d837133d..69ff29d3a1 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp @@ -24,12 +24,9 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWidgetDragger::RiuWidgetDragger( QWidget* widgetToMove, - QWidget* widgetToSnapTo /*= nullptr*/, - int snapMargins /*= 5*/ ) +RiuWidgetDragger::RiuWidgetDragger( QWidget* widgetToMove, int snapMargins /*= 5*/ ) : QObject( widgetToMove ) , m_widgetToMove( widgetToMove ) - , m_widgetToSnapTo( widgetToSnapTo ) , m_snapMargins( snapMargins ) , m_startPos( 0, 0 ) { @@ -56,61 +53,58 @@ bool RiuWidgetDragger::eventFilter( QObject* watched, QEvent* event ) { QPoint relativeMove = mMoveEv->pos() - m_startPos; QRect newFrameRect = m_widgetToMove->frameGeometry().translated( relativeMove ); + QRect snapToRect = m_widgetToMove->parentWidget()->rect(); - if ( m_widgetToSnapTo ) { - QRect snapToRect = m_widgetToSnapTo->frameGeometry(); + QPoint snapToTopLeft = snapToRect.topLeft(); + QPoint widgetTopLeft = newFrameRect.topLeft(); + QPoint diff = snapToTopLeft - widgetTopLeft; + if ( std::abs( diff.x() ) < 4 * m_snapMargins ) { - QPoint snapToTopLeft = snapToRect.topLeft(); - QPoint widgetTopLeft = newFrameRect.topLeft(); - QPoint diff = snapToTopLeft - widgetTopLeft; - if ( std::abs( diff.x() ) < 4 * m_snapMargins ) - { - newFrameRect.moveLeft( snapToTopLeft.x() + m_snapMargins ); - } - if ( std::abs( diff.y() ) < 4 * m_snapMargins ) - { - newFrameRect.moveTop( snapToTopLeft.y() + m_snapMargins ); - } + newFrameRect.moveLeft( snapToTopLeft.x() + m_snapMargins ); } + if ( std::abs( diff.y() ) < 4 * m_snapMargins ) { - QPoint snapToBottomLeft = snapToRect.bottomLeft(); - QPoint widgetBottomLeft = newFrameRect.bottomLeft(); - QPoint diff = snapToBottomLeft - widgetBottomLeft; - if ( std::abs( diff.x() ) < 4 * m_snapMargins ) - { - newFrameRect.moveLeft( snapToBottomLeft.x() + m_snapMargins ); - } - if ( std::abs( diff.y() ) < 4 * m_snapMargins ) - { - newFrameRect.moveBottom( snapToBottomLeft.y() - m_snapMargins ); - } + newFrameRect.moveTop( snapToTopLeft.y() + m_snapMargins ); } + } + { + QPoint snapToBottomLeft = snapToRect.bottomLeft(); + QPoint widgetBottomLeft = newFrameRect.bottomLeft(); + QPoint diff = snapToBottomLeft - widgetBottomLeft; + if ( std::abs( diff.x() ) < 4 * m_snapMargins ) { - QPoint snapToTopRight = snapToRect.topRight(); - QPoint widgetTopRight = newFrameRect.topRight(); - QPoint diff = snapToTopRight - widgetTopRight; - if ( std::abs( diff.x() ) < 4 * m_snapMargins ) - { - newFrameRect.moveRight( snapToTopRight.x() - m_snapMargins ); - } - if ( std::abs( diff.y() ) < 4 * m_snapMargins ) - { - newFrameRect.moveTop( snapToTopRight.y() + m_snapMargins ); - } + newFrameRect.moveLeft( snapToBottomLeft.x() + m_snapMargins ); } + if ( std::abs( diff.y() ) < 4 * m_snapMargins ) { - QPoint snapToBottomRight = snapToRect.bottomRight(); - QPoint widgetBottomRight = newFrameRect.bottomRight(); - QPoint diff = snapToBottomRight - widgetBottomRight; - if ( std::abs( diff.x() ) < 4 * m_snapMargins ) - { - newFrameRect.moveRight( snapToBottomRight.x() - m_snapMargins ); - } - if ( std::abs( diff.y() ) < 4 * m_snapMargins ) - { - newFrameRect.moveBottom( snapToBottomRight.y() - m_snapMargins ); - } + newFrameRect.moveBottom( snapToBottomLeft.y() - m_snapMargins ); + } + } + { + QPoint snapToTopRight = snapToRect.topRight(); + QPoint widgetTopRight = newFrameRect.topRight(); + QPoint diff = snapToTopRight - widgetTopRight; + if ( std::abs( diff.x() ) < 4 * m_snapMargins ) + { + newFrameRect.moveRight( snapToTopRight.x() - m_snapMargins ); + } + if ( std::abs( diff.y() ) < 4 * m_snapMargins ) + { + newFrameRect.moveTop( snapToTopRight.y() + m_snapMargins ); + } + } + { + QPoint snapToBottomRight = snapToRect.bottomRight(); + QPoint widgetBottomRight = newFrameRect.bottomRight(); + QPoint diff = snapToBottomRight - widgetBottomRight; + if ( std::abs( diff.x() ) < 4 * m_snapMargins ) + { + newFrameRect.moveRight( snapToBottomRight.x() - m_snapMargins ); + } + if ( std::abs( diff.y() ) < 4 * m_snapMargins ) + { + newFrameRect.moveBottom( snapToBottomRight.y() - m_snapMargins ); } } m_widgetToMove->move( newFrameRect.topLeft() ); diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.h b/ApplicationCode/UserInterface/RiuWidgetDragger.h index 6c4849f8e4..9f19fd652f 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.h +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.h @@ -28,14 +28,13 @@ class RiuWidgetDragger : public QObject { Q_OBJECT public: - RiuWidgetDragger( QWidget* widgetToMove, QWidget* widgetToSnapTo = nullptr, int snapMargins = 5 ); + RiuWidgetDragger( QWidget* widgetToMove, int snapMargins = 5 ); void addWidget( QWidget* widget ); bool eventFilter( QObject* watched, QEvent* event ) override; private: QPointer m_widgetToMove; - QPointer m_widgetToSnapTo; int m_snapMargins; QPoint m_startPos; }; diff --git a/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.cpp b/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.cpp index c1eb88ac3e..138b917e50 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.cpp @@ -30,6 +30,7 @@ #include "cafInternalLegendRenderTools.h" #include +#include using namespace cvf; diff --git a/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h b/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h index 3a8f67d156..69868daecc 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h +++ b/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h @@ -38,13 +38,13 @@ public: void majorTickValues(std::vector* domainValues) const override; double normalizedValue(double domainValue) const override; double domainValue(double normalizedValue) const override; + size_t categoryCount() const; + + const cvf::String textForCategoryIndex(size_t index) const; + int categoryIndexForCategory(double domainValue) const; private: - friend class CategoryLegend; - size_t categoryCount() const; - const cvf::String textForCategoryIndex(size_t index) const; - int categoryIndexForCategory(double domainValue) const; void recomputeMaxTexCoord(); private: diff --git a/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.cpp b/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.cpp index 7cf1630953..937c5ff36e 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.cpp @@ -682,7 +682,7 @@ cvf::Vec2ui OverlayScalarMapperLegend::preferredSize() OverlayColorLegendLayoutInfo layout({200,200}); // Use default size layoutInfo(&layout); - float prefferredYSize = 2 * layout.margins.y() + float preferredYSize = 2 * layout.margins.y() + layout.lineSpacing * this->titleStrings().size() + 1.5f * layout.lineSpacing * m_tickValues.size(); @@ -706,18 +706,17 @@ cvf::Vec2ui OverlayScalarMapperLegend::preferredSize() maxTickTextWidth = maxTickTextWidth < textWidth ? textWidth : maxTickTextWidth; } - float prefferredXSize = layout.tickEndX + layout.margins.x() + layout.tickTextLeadSpace + maxTickTextWidth; + float preferredXSize = layout.tickEndX + layout.margins.x() + layout.tickTextLeadSpace + maxTickTextWidth; for (const cvf::String& titleLine : titleStrings()) { float titleWidth = this->font()->textExtent(titleLine).x() + 2*layout.margins.x(); - prefferredXSize = prefferredXSize < titleWidth ? titleWidth : prefferredXSize; + preferredXSize = preferredXSize < titleWidth ? titleWidth : preferredXSize; } - prefferredXSize = std::min(prefferredXSize, 400.0f); - - return { (unsigned int)(std::ceil(prefferredXSize)), (unsigned int)(std::ceil(prefferredYSize)) }; + preferredXSize = std::min(preferredXSize, 400.0f); + return { (unsigned int)(std::ceil(preferredXSize)), (unsigned int)(std::ceil(preferredYSize)) }; } } // namespace cvf diff --git a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp index e13bf802d6..aeab31ff1e 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp @@ -218,4 +218,4 @@ namespace caf { { return m_font.p(); } -} \ No newline at end of file +} diff --git a/ThirdParty/Qwt/src/qwt_plot_canvas.cpp b/ThirdParty/Qwt/src/qwt_plot_canvas.cpp index 9438f15fcf..bac15353f7 100644 --- a/ThirdParty/Qwt/src/qwt_plot_canvas.cpp +++ b/ThirdParty/Qwt/src/qwt_plot_canvas.cpp @@ -730,7 +730,7 @@ void QwtPlotCanvas::paintEvent( QPaintEvent *event ) QPainter painter( this ); painter.setClipRegion( event->region() ); - if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) && + if (testPaintAttribute( QwtPlotCanvas::BackingStore ) && d_data->backingStore != NULL ) { QPixmap &bs = *d_data->backingStore;