diff --git a/ApplicationLibCode/Commands/ApplicationCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/ApplicationCommands/CMakeLists_files.cmake index d66c1d2472..1ef296520c 100644 --- a/ApplicationLibCode/Commands/ApplicationCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/ApplicationCommands/CMakeLists_files.cmake @@ -17,7 +17,6 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportObjectAndFieldKeywordsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveProjectNoGlobalPathsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicShowClassNamesFeature.cpp - ${CMAKE_CURRENT_LIST_DIR}/RicShowPlotDataCtxFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicOpenInTextEditorFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicShowMemoryReportFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSumoDataFeature.cpp diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.cpp b/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.cpp deleted file mode 100644 index 37834b46b8..0000000000 --- a/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.cpp +++ /dev/null @@ -1,29 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2022 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 "RicShowPlotDataCtxFeature.h" - -CAF_CMD_SOURCE_INIT( RicShowPlotDataCtxFeature, "RicShowPlotDataCtxFeature" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicShowPlotDataCtxFeature::isCommandEnabled() const -{ - return true; -} diff --git a/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.h b/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.h deleted file mode 100644 index b1eb2b90b2..0000000000 --- a/ApplicationLibCode/Commands/ApplicationCommands/RicShowPlotDataCtxFeature.h +++ /dev/null @@ -1,32 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2022 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 "RicShowPlotDataFeature.h" - -//================================================================================================== -/// -//================================================================================================== -class RicShowPlotDataCtxFeature : public RicShowPlotDataFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - bool isCommandEnabled() const override; -}; diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake index d4134b1659..a3bfe916f4 100644 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/SummaryPlotCommands/CMakeLists_files.cmake @@ -39,7 +39,6 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicShowSummaryPlotManagerFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicPasteSummaryMultiPlotFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicDeleteSubPlotCtxFeature.cpp - ${CMAKE_CURRENT_LIST_DIR}/RicEditSummaryPlotCtxFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicToggleYAxisLinkingFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicToggleXAxisLinkingFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicOpenSummaryPlotEditorFromMdiAreaFeature.cpp diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.cpp b/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.cpp deleted file mode 100644 index ef949ea4c4..0000000000 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.cpp +++ /dev/null @@ -1,29 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2022 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 "RicEditSummaryPlotCtxFeature.h" - -CAF_CMD_SOURCE_INIT( RicEditSummaryPlotCtxFeature, "RicEditSummaryPlotCtxFeature" ); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicEditSummaryPlotCtxFeature::isCommandEnabled() const -{ - return true; -} diff --git a/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.h b/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.h deleted file mode 100644 index 6abb23b29b..0000000000 --- a/ApplicationLibCode/Commands/SummaryPlotCommands/RicEditSummaryPlotCtxFeature.h +++ /dev/null @@ -1,32 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2022 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 "RicEditSummaryPlotFeature.h" - -//================================================================================================== -/// -//================================================================================================== -class RicEditSummaryPlotCtxFeature : public RicEditSummaryPlotFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - bool isCommandEnabled() const override; -}; diff --git a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp index 7990e9dfa3..84e61ed82e 100644 --- a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.cpp @@ -995,6 +995,81 @@ std::pair RiuQwtPlotWidget::findClosestCurve( const QPoint& return std::make_pair( plotCurve, closestCurvePoint ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::highlightClosestPlotItemAtPosition( const QPoint& widgetPos ) +{ + // highlightClosestPlotItem expects canvas coordinates, while widgetPos is given in widget coordinates. + QPoint canvasPos = qwtPlot()->canvas()->mapFromGlobal( mapToGlobal( widgetPos ) ); + highlightClosestPlotItem( canvasPos ); +} + +//-------------------------------------------------------------------------------------------------- +/// Applies the visual highlight for the closest plot item, without changing the project tree / selection manager +/// selection. Shared by selectClosestPlotItem (which additionally updates the selection) and highlightClosestPlotItem. +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::applyHighlightForClosestItem( QwtPlotItem* closestItem, const std::vector& curvesToHighlight ) +{ + bool updateCurveOrder = false; + resetPlotItemHighlighting( updateCurveOrder ); + + if ( !curvesToHighlight.empty() ) + { + if ( RimSummaryEnsembleTools::isEnsembleCurve( curvesToHighlight.front() ) ) + { + auto summaryCases = RimSummaryEnsembleTools::summaryCasesFromCurves( curvesToHighlight ); + RimSummaryEnsembleTools::highlightCurvesForSummaryCases( summaryCases ); + } + else + { + highlightCurvesUpdateOrder( curvesToHighlight ); + } + } + else if ( closestItem ) + { + // Currently used from the matrix plot to highlight the selected cell in the matrix plot, see + // RimCorrelationMatrixPlot::createMatrix() + highlightPlotShapeItems( { closestItem } ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotWidget::highlightClosestPlotItem( const QPoint& pos ) +{ + QwtPlotItem* closestItem = nullptr; + double distanceFromClick = std::numeric_limits::infinity(); + int closestCurvePoint = -1; + + findClosestPlotItem( pos, &closestItem, &closestCurvePoint, &distanceFromClick ); + + if ( closestItem ) + { + RimPlotCurve* closestCurve = nullptr; + if ( auto curve = dynamic_cast( closestItem ) ) + { + closestCurve = curve->ownerRimCurve(); + } + + std::vector curvesToHighlight; + if ( closestCurve && distanceFromClick < 100 ) + { + curvesToHighlight.push_back( closestCurve ); + } + + applyHighlightForClosestItem( closestItem, curvesToHighlight ); + } + else + { + RimSummaryEnsembleTools::resetHighlightAllPlots(); + } + + // Always do a replot, as the reset operation also requires replot + replot(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1042,28 +1117,13 @@ void RiuQwtPlotWidget::selectClosestPlotItem( const QPoint& pos, bool toggleItem } } - bool updateCurveOrder = false; - resetPlotItemHighlighting( updateCurveOrder ); + if ( !curvesToSelect.empty() && RimSummaryEnsembleTools::isEnsembleCurve( curvesToSelect.front() ) ) + { + auto summaryCases = RimSummaryEnsembleTools::summaryCasesFromCurves( curvesToSelect ); + RimSummaryEnsembleTools::selectSummaryCasesInProjectTree( summaryCases ); + } - if ( !curvesToSelect.empty() ) - { - if ( RimSummaryEnsembleTools::isEnsembleCurve( curvesToSelect.front() ) ) - { - auto summaryCases = RimSummaryEnsembleTools::summaryCasesFromCurves( curvesToSelect ); - RimSummaryEnsembleTools::selectSummaryCasesInProjectTree( summaryCases ); - RimSummaryEnsembleTools::highlightCurvesForSummaryCases( summaryCases ); - } - else - { - highlightCurvesUpdateOrder( curvesToSelect ); - } - } - else - { - // Currently used from the matrix plot to highlight the selected cell in the matrix plot, see - // RimCorrelationMatrixPlot::createMatrix() - highlightPlotShapeItems( { closestItem } ); - } + applyHighlightForClosestItem( closestItem, curvesToSelect ); auto plotItem = std::make_shared( closestItem ); emit plotItemSelected( plotItem, toggleItemInSelection, distanceFromClick < 10 ? closestCurvePoint : -1 ); diff --git a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h index 50b4dbd2be..963d6d49a0 100644 --- a/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuQwtPlotWidget.h @@ -167,6 +167,10 @@ public: void resetPlotItemHighlighting( bool doUpdateCurveOrder = true ); std::vector> highlightedCurves() const; + // Highlights the plot item closest to the given position, given in widget coordinates. Unlike a left-click, this + // only applies the visual highlight and does not change the project tree / selection manager selection. + void highlightClosestPlotItemAtPosition( const QPoint& widgetPos ); + void replot() override; public slots: @@ -205,6 +209,8 @@ protected: private: void selectClosestPlotItem( const QPoint& pos, bool toggleItemInSelection = false ); + void highlightClosestPlotItem( const QPoint& pos ); + void applyHighlightForClosestItem( QwtPlotItem* closestItem, const std::vector& curvesToHighlight ); void findClosestPlotItem( const QPoint& pos, QwtPlotItem** closestItem, int* closestCurveSampleIndex, double* distanceFromClick ) const; static int defaultMinimumWidth(); diff --git a/ApplicationLibCode/UserInterface/RiuSummaryPlot.cpp b/ApplicationLibCode/UserInterface/RiuSummaryPlot.cpp index 4e8fcd7339..1840b8117e 100644 --- a/ApplicationLibCode/UserInterface/RiuSummaryPlot.cpp +++ b/ApplicationLibCode/UserInterface/RiuSummaryPlot.cpp @@ -29,8 +29,10 @@ #include "RiuPlotCurve.h" #include "RiuPlotWidget.h" +#include "RiuQwtPlotWidget.h" #include "cafCmdFeatureMenuBuilder.h" +#include "cafSelectionManager.h" #include #include @@ -59,24 +61,38 @@ void RiuSummaryPlot::showContextMenu( QPoint pos ) { if ( !plotWidget() ) return; + // Highlight the curve under the cursor before showing the menu, giving the same visual feedback as a left-click. + // Only the highlight is applied, not a selection change, so the plot is selected as the current item below. + if ( auto* qwtPlotWidget = dynamic_cast( plotWidget() ) ) + { + qwtPlotWidget->highlightClosestPlotItemAtPosition( pos ); + } + QMenu menu; caf::CmdFeatureMenuBuilder menuBuilder; RimSummaryPlot* plot = dynamic_cast( plotWidget()->plotDefinition() ); + + // Select the plot before any menu commands are created, so the commands operate on this plot. This lets the plot + // commands below resolve the plot from the selection, instead of passing it as user data. + if ( plot ) caf::SelectionManager::instance()->setSelectedItem( plot ); + if ( plot ) { - QVariant plotVariant( QVariant::fromValue( static_cast( plot ) ) ); - menuBuilder.addCmdFeatureWithUserData( "RicShowPlotDataCtxFeature", "Show Plot Data", plotVariant ); - menuBuilder.addCmdFeatureWithUserData( "RicEditSummaryPlotCtxFeature", "Edit Plot", plotVariant ); - menuBuilder.addCmdFeatureWithUserData( "RicSplitMultiPlotFeature", "Split into Multiple Plots", plotVariant ); + menuBuilder.addCmdFeature( "RicShowPlotDataFeature" ); + menuBuilder.addCmdFeature( "RicEditSummaryPlotFeature" ); + menuBuilder.addCmdFeature( "RicSplitMultiPlotFeature" ); menuBuilder.addSeparator(); - menuBuilder.addCmdFeatureWithUserData( "RicDeleteSubPlotCtxFeature", "Delete Plot", plotVariant ); + menuBuilder.addCmdFeature( "RicDeleteSubPlotCtxFeature" ); menuBuilder.addSeparator(); for ( auto curveSet : plot->curveSets() ) { if ( curveSet->isFiltered() ) { + // Offer to create a new ensemble from the cases currently passing the curve set's filter. The curve set + // is passed as user data, as a plot can contain several filtered curve sets and the selected plot alone + // does not identify which one to use. auto curveSetVariant = QVariant::fromValue( caf::PdmPointer( curveSet ) ); auto name = "Create Ensemble from Filtered Cases: " + curveSet->name(); menuBuilder.addCmdFeatureWithUserData( "RicCreateEnsembleFromFilteredCasesFeature", name, curveSetVariant );