mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 06:38:13 -05:00
Summary plot: select plot before building the right-click context menu
Select the summary plot as the current item before any menu commands are created, so every command in the context menu operates on that plot. This is the root fix for plot-level commands (New Analysis Plot, correlation plots, etc.) that derive their enablement from the selected plot: previously the selection could be left on an ensemble realization's summary case, disabling them. Because the plot is now selected, the Show Plot Data / Edit Plot / Split / Delete commands resolve the plot from the selection, so passing it as user data is no longer needed. The RicShowPlotDataCtxFeature and RicEditSummaryPlotCtxFeature subclasses existed only to force isCommandEnabled to true for the context menu; they are now obsolete and removed, and the menu uses the base RicShowPlotData and RicEditSummaryPlot features directly. Also highlight the curve under the cursor before showing the menu, giving the same visual feedback as a left-click. Separate highlighting from selection: extract the visual-only part of selectClosestPlotItem into applyHighlightForClosestItem, shared by selectClosestPlotItem (left-click: highlight + select) and the new highlightClosestPlotItem (highlight only). The context menu uses the highlight-only path, so it does not change the selection. Add highlightClosestPlotItemAtPosition that takes widget coordinates and converts them to canvas coordinates internally, so the caller does not depend on qwt headers.
This commit is contained in:
1 parent
8606fa002e
commit
c6591eac95
9 files changed
+108
-150
No files matched your search
@@ -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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicShowPlotDataCtxFeature.h"
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicShowPlotDataCtxFeature, "RicShowPlotDataCtxFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicShowPlotDataCtxFeature::isCommandEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RicShowPlotDataFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicShowPlotDataCtxFeature : public RicShowPlotDataFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
bool isCommandEnabled() const override;
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "RicEditSummaryPlotCtxFeature.h"
|
||||
|
||||
CAF_CMD_SOURCE_INIT( RicEditSummaryPlotCtxFeature, "RicEditSummaryPlotCtxFeature" );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RicEditSummaryPlotCtxFeature::isCommandEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/gpl.html>
|
||||
// for more details.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RicEditSummaryPlotFeature.h"
|
||||
|
||||
//==================================================================================================
|
||||
///
|
||||
//==================================================================================================
|
||||
class RicEditSummaryPlotCtxFeature : public RicEditSummaryPlotFeature
|
||||
{
|
||||
CAF_CMD_HEADER_INIT;
|
||||
|
||||
protected:
|
||||
bool isCommandEnabled() const override;
|
||||
};
|
||||
@@ -995,6 +995,81 @@ std::pair<RiuPlotCurve*, int> 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<RimPlotCurve*>& 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<double>::infinity();
|
||||
int closestCurvePoint = -1;
|
||||
|
||||
findClosestPlotItem( pos, &closestItem, &closestCurvePoint, &distanceFromClick );
|
||||
|
||||
if ( closestItem )
|
||||
{
|
||||
RimPlotCurve* closestCurve = nullptr;
|
||||
if ( auto curve = dynamic_cast<RiuPlotCurve*>( closestItem ) )
|
||||
{
|
||||
closestCurve = curve->ownerRimCurve();
|
||||
}
|
||||
|
||||
std::vector<RimPlotCurve*> 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<RiuQwtPlotItem>( closestItem );
|
||||
emit plotItemSelected( plotItem, toggleItemInSelection, distanceFromClick < 10 ? closestCurvePoint : -1 );
|
||||
|
||||
@@ -167,6 +167,10 @@ public:
|
||||
void resetPlotItemHighlighting( bool doUpdateCurveOrder = true );
|
||||
std::vector<caf::PdmPointer<RimPlotCurve>> 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<RimPlotCurve*>& curvesToHighlight );
|
||||
void findClosestPlotItem( const QPoint& pos, QwtPlotItem** closestItem, int* closestCurveSampleIndex, double* distanceFromClick ) const;
|
||||
|
||||
static int defaultMinimumWidth();
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
|
||||
#include "RiuPlotCurve.h"
|
||||
#include "RiuPlotWidget.h"
|
||||
#include "RiuQwtPlotWidget.h"
|
||||
|
||||
#include "cafCmdFeatureMenuBuilder.h"
|
||||
#include "cafSelectionManager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
@@ -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<RiuQwtPlotWidget*>( plotWidget() ) )
|
||||
{
|
||||
qwtPlotWidget->highlightClosestPlotItemAtPosition( pos );
|
||||
}
|
||||
|
||||
QMenu menu;
|
||||
caf::CmdFeatureMenuBuilder menuBuilder;
|
||||
|
||||
RimSummaryPlot* plot = dynamic_cast<RimSummaryPlot*>( 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<void*>( 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<RimEnsembleCurveSet>( curveSet ) );
|
||||
auto name = "Create Ensemble from Filtered Cases: " + curveSet->name();
|
||||
menuBuilder.addCmdFeatureWithUserData( "RicCreateEnsembleFromFilteredCasesFeature", name, curveSetVariant );
|
||||
|
||||
Reference in new issue
Block a user