From cdaa58b6c80122881d86639332f6ec9b8dc29148 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 16 Feb 2026 14:59:40 +0100 Subject: [PATCH 1/5] Do not update the HUD during de-serialization, do it post-de-serialization. Put guard in updateHeadsUpDisplay --- src/ScatterplotPlugin.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ScatterplotPlugin.cpp b/src/ScatterplotPlugin.cpp index 94d4826..5357bbc 100644 --- a/src/ScatterplotPlugin.cpp +++ b/src/ScatterplotPlugin.cpp @@ -288,6 +288,8 @@ ScatterplotPlugin::ScatterplotPlugin(const PluginFactory* factory) : getLearningCenterAction().addVideos(QStringList({ "Practitioner", "Developer" })); setOverlayActionsTargetWidget(_scatterPlotWidget); + + connect(&mv::projects(), &AbstractProjectManager::projectOpened, this, &ScatterplotPlugin::updateHeadsUpDisplay); } ScatterplotPlugin::~ScatterplotPlugin() @@ -1016,6 +1018,9 @@ void ScatterplotPlugin::updateSelection() void ScatterplotPlugin::updateHeadsUpDisplay() { + if (mv::projects().isOpeningProject()) + return; + getHeadsUpDisplayAction().removeAllHeadsUpDisplayItems(); if (_positionDataset.isValid()) { @@ -1037,6 +1042,7 @@ void ScatterplotPlugin::updateHeadsUpDisplay() } else { getHeadsUpDisplayAction().addHeadsUpDisplayItem("No datasets loaded", "", ""); } + } void ScatterplotPlugin::updateHeadsUpDisplayTextColor() @@ -1065,12 +1071,7 @@ void ScatterplotPlugin::fromVariantMap(const QVariantMap& variantMap) _primaryToolbarAction.fromParentVariantMap(variantMap); _settingsAction.fromParentVariantMap(variantMap); - updateHeadsUpDisplay(); - if (pointRenderer.getNavigator().getNavigationAction().getSerializationCountFrom() == 0) { - qDebug() << "Resetting view"; - - _scatterPlotWidget->update(); } From 1b2782ba6acff760f844efedab224520b9f575f9 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Mon, 16 Feb 2026 16:28:04 +0100 Subject: [PATCH 2/5] Properly sync HUD with loaded color, point size and point opacity dataset(s) --- src/ScatterplotPlugin.cpp | 36 +++++++++++++++++++++++++++++------- src/ScatterplotPlugin.h | 4 +++- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/ScatterplotPlugin.cpp b/src/ScatterplotPlugin.cpp index 5357bbc..9adb621 100644 --- a/src/ScatterplotPlugin.cpp +++ b/src/ScatterplotPlugin.cpp @@ -344,9 +344,6 @@ void ScatterplotPlugin::init() connect(&_positionDataset, &Dataset<>::guiNameChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); const auto currentColorDatasetChanged = [this](Dataset currentColorDataset) -> void { - if (_colorDataset == currentColorDataset) - return; - if (_colorDataset.isValid()) disconnect(&_colorDataset, &Dataset<>::guiNameChanged, this, nullptr); @@ -362,8 +359,35 @@ void ScatterplotPlugin::init() currentColorDatasetChanged(_settingsAction.getColoringAction().getCurrentColorDataset()); }); - connect(&_settingsAction.getPlotAction().getPointPlotAction().getSizeAction(), &ScalarAction::sourceDataChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); - connect(&_settingsAction.getPlotAction().getPointPlotAction().getOpacityAction(), &ScalarAction::sourceDataChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + const auto currentPointSizeDatasetChanged = [this]() -> void { + auto currentPointSizeDataset = _settingsAction.getPlotAction().getPointPlotAction().getSizeAction().getCurrentDataset(); + + if (_pointSizeDataset.isValid()) + disconnect(&_pointSizeDataset, &Dataset<>::guiNameChanged, this, nullptr); + + _pointSizeDataset = currentPointSizeDataset; + + connect(&_pointSizeDataset, &Dataset<>::guiNameChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + + updateHeadsUpDisplay(); + }; + + connect(&_settingsAction.getPlotAction().getPointPlotAction().getSizeAction(), &ScalarAction::sourceSelectionChanged, this, currentPointSizeDatasetChanged); + + const auto currentPointOpacityDatasetChanged = [this]() -> void { + auto currentPointOpacityDataset = _settingsAction.getPlotAction().getPointPlotAction().getOpacityAction().getCurrentDataset(); + + if (_pointOpacityDataset.isValid()) + disconnect(&_pointOpacityDataset, &Dataset<>::guiNameChanged, this, nullptr); + + _pointOpacityDataset = currentPointOpacityDataset; + + connect(&_pointOpacityDataset, &Dataset<>::guiNameChanged, this, &ScatterplotPlugin::updateHeadsUpDisplay); + + updateHeadsUpDisplay(); + }; + + connect(&_settingsAction.getPlotAction().getPointPlotAction().getOpacityAction(), &ScalarAction::sourceSelectionChanged, this, currentPointOpacityDatasetChanged); connect(&_settingsAction.getMiscellaneousAction().getBackgroundColorAction(), &ColorAction::colorChanged, this, &ScatterplotPlugin::updateHeadsUpDisplayTextColor); @@ -1038,11 +1062,9 @@ void ScatterplotPlugin::updateHeadsUpDisplay() addMetaDataToHeadsUpDisplay("Size", _settingsAction.getPlotAction().getPointPlotAction().getSizeAction().getCurrentDataset(), datasetsItem); addMetaDataToHeadsUpDisplay("Opacity", _settingsAction.getPlotAction().getPointPlotAction().getOpacityAction().getCurrentDataset(), datasetsItem); - } else { getHeadsUpDisplayAction().addHeadsUpDisplayItem("No datasets loaded", "", ""); } - } void ScatterplotPlugin::updateHeadsUpDisplayTextColor() diff --git a/src/ScatterplotPlugin.h b/src/ScatterplotPlugin.h index 4155039..301364d 100644 --- a/src/ScatterplotPlugin.h +++ b/src/ScatterplotPlugin.h @@ -116,7 +116,9 @@ class ScatterplotPlugin : public ViewPlugin ScatterplotWidget* _scatterPlotWidget; /** The visualization widget */ Dataset _positionDataset; /** Smart pointer to points dataset for point position */ Dataset _positionSourceDataset; /** Smart pointer to source of the points dataset for point position (if any) */ - Dataset _colorDataset; /** Smart pointer to dataset used for coloring (if any) */ + Dataset _colorDataset; /** Smart pointer to dataset used for coloring (if any) */ + Dataset _pointSizeDataset; /** Smart pointer to dataset for driving point size (if any) */ + Dataset _pointOpacityDataset; /** Smart pointer to dataset for driving point opacity (if any) */ std::vector _positions; /** Point positions */ unsigned int _numPoints; /** Number of point positions */ SettingsAction _settingsAction; /** Group action for all settings */ From 14881c10fb0447cba928d6acf908e31a6281924b Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 17 Feb 2026 09:55:00 +0100 Subject: [PATCH 3/5] Addd point size and opacity dataset picker actions and implement the synchronization logic --- src/DatasetsAction.cpp | 55 +++++++++++++++++++++++++++++++++++++++--- src/DatasetsAction.h | 4 +++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/DatasetsAction.cpp b/src/DatasetsAction.cpp index 3cc6381..247f338 100644 --- a/src/DatasetsAction.cpp +++ b/src/DatasetsAction.cpp @@ -14,7 +14,9 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : GroupAction(parent, title), _scatterplotPlugin(dynamic_cast(parent->parent())), _positionDatasetPickerAction(this, "Position"), - _colorDatasetPickerAction(this, "Color") + _colorDatasetPickerAction(this, "Color"), + _pointSizeDatasetPickerAction(this, "Point size"), + _pointOpacityDatasetPickerAction(this, "Point opacity") { setIconByName("database"); setToolTip("Manage loaded datasets for position and color"); @@ -23,15 +25,24 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : addAction(&_positionDatasetPickerAction); addAction(&_colorDatasetPickerAction); + addAction(&_pointSizeDatasetPickerAction); + addAction(&_pointOpacityDatasetPickerAction); _positionDatasetPickerAction.setFilterFunction([this](mv::Dataset dataset) -> bool { return dataset->getDataType() == PointType; - }); + }); _colorDatasetPickerAction.setFilterFunction([this](mv::Dataset dataset) -> bool { return (dataset->getDataType() == PointType || dataset->getDataType() == ColorType || dataset->getDataType() == ClusterType); - }); + }); + + _pointSizeDatasetPickerAction.setFilterFunction([this](mv::Dataset dataset) -> bool { + return dataset->getDataType() == PointType; + }); + _pointOpacityDatasetPickerAction.setFilterFunction([this](mv::Dataset dataset) -> bool { + return dataset->getDataType() == PointType; + }); auto scatterplotPlugin = dynamic_cast(parent->parent()); @@ -53,6 +64,44 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : connect(&scatterplotPlugin->getSettingsAction().getColoringAction(), &ColoringAction::currentColorDatasetChanged, this, [this](Dataset currentColorDataset) -> void { _colorDatasetPickerAction.setCurrentDataset(currentColorDataset); }); + + auto& pointPlotAction = scatterplotPlugin->getSettingsAction().getPlotAction().getPointPlotAction(); + auto& pointSizeAction = pointPlotAction.getSizeAction(); + auto& pointOpacityAction = pointPlotAction.getOpacityAction(); + + const auto pointSizeSourceChanged = [this, &pointSizeAction]() -> void { + _pointSizeDatasetPickerAction.setCurrentDataset(pointSizeAction.isSourceDataset() ? pointSizeAction.getCurrentDataset() : nullptr); + + if (!pointSizeAction.isSourceDataset()) + _pointSizeDatasetPickerAction.setCurrentIndex(-1); + }; + + connect(&pointSizeAction, &ScalarAction::sourceSelectionChanged, this, pointSizeSourceChanged); + connect(&pointSizeAction, &ScalarAction::sourceDataChanged, this, pointSizeSourceChanged); + + connect(&_pointSizeDatasetPickerAction, &DatasetPickerAction::datasetPicked, this, [this, &pointSizeAction](Dataset dataset) -> void { + if (!dataset.isValid()) + return; + + pointSizeAction.setCurrentDataset(dataset); + }); + + const auto pointOpacitySourceChanged = [this, &pointOpacityAction]() -> void { + _pointOpacityDatasetPickerAction.setCurrentDataset(pointOpacityAction.isSourceDataset() ? pointOpacityAction.getCurrentDataset() : nullptr); + + if (!pointOpacityAction.isSourceDataset()) + _pointOpacityDatasetPickerAction.setCurrentIndex(-1); + }; + + connect(&pointOpacityAction, &ScalarAction::sourceSelectionChanged, this, pointOpacitySourceChanged); + connect(&pointOpacityAction, &ScalarAction::sourceDataChanged, this, pointOpacitySourceChanged); + + connect(&_pointOpacityDatasetPickerAction, &DatasetPickerAction::datasetPicked, this, [this, &pointOpacityAction](Dataset dataset) -> void { + if (!dataset.isValid()) + return; + + pointOpacityAction.setCurrentDataset(dataset); + }); } void DatasetsAction::connectToPublicAction(WidgetAction* publicAction, bool recursive) diff --git a/src/DatasetsAction.h b/src/DatasetsAction.h index 1730a06..db10a3e 100644 --- a/src/DatasetsAction.h +++ b/src/DatasetsAction.h @@ -53,11 +53,15 @@ class DatasetsAction : public GroupAction DatasetPickerAction& getPositionDatasetPickerAction() { return _positionDatasetPickerAction; } DatasetPickerAction& getColorDatasetPickerAction() { return _colorDatasetPickerAction; } + DatasetPickerAction& getPointSizeDatasetPickerAction() { return _pointSizeDatasetPickerAction; } + DatasetPickerAction& getPointOpacityDatasetPickerAction() { return _pointOpacityDatasetPickerAction; } private: ScatterplotPlugin* _scatterplotPlugin; /** Pointer to scatter plot plugin */ DatasetPickerAction _positionDatasetPickerAction; /** Dataset picker action for position dataset */ DatasetPickerAction _colorDatasetPickerAction; /** Dataset picker action for color dataset */ + DatasetPickerAction _pointSizeDatasetPickerAction; /** Dataset picker action for point size */ + DatasetPickerAction _pointOpacityDatasetPickerAction; /** Dataset picker action for point opacity */ friend class mv::AbstractActionsManager; }; From 7d2e9a9c449fb758b6b7a749368331006b5630e0 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 17 Feb 2026 09:56:21 +0100 Subject: [PATCH 4/5] Add connection logic --- src/DatasetsAction.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/DatasetsAction.cpp b/src/DatasetsAction.cpp index 247f338..095442d 100644 --- a/src/DatasetsAction.cpp +++ b/src/DatasetsAction.cpp @@ -116,6 +116,8 @@ void DatasetsAction::connectToPublicAction(WidgetAction* publicAction, bool recu if (recursive) { actions().connectPrivateActionToPublicAction(&_positionDatasetPickerAction, &publicDatasetsAction->getPositionDatasetPickerAction(), recursive); actions().connectPrivateActionToPublicAction(&_colorDatasetPickerAction, &publicDatasetsAction->getColorDatasetPickerAction(), recursive); + actions().connectPrivateActionToPublicAction(&_pointSizeDatasetPickerAction, &publicDatasetsAction->getPointSizeDatasetPickerAction(), recursive); + actions().connectPrivateActionToPublicAction(&_pointOpacityDatasetPickerAction, &publicDatasetsAction->getPointOpacityDatasetPickerAction(), recursive); } GroupAction::connectToPublicAction(publicAction, recursive); @@ -129,6 +131,8 @@ void DatasetsAction::disconnectFromPublicAction(bool recursive) if (recursive) { actions().disconnectPrivateActionFromPublicAction(&_positionDatasetPickerAction, recursive); actions().disconnectPrivateActionFromPublicAction(&_colorDatasetPickerAction, recursive); + actions().disconnectPrivateActionFromPublicAction(&_pointSizeDatasetPickerAction, recursive); + actions().disconnectPrivateActionFromPublicAction(&_pointOpacityDatasetPickerAction, recursive); } GroupAction::disconnectFromPublicAction(recursive); From a373ebb27554a4f88a44de16310efd5ae2501d67 Mon Sep 17 00:00:00 2001 From: Thomas Kroes Date: Tue, 17 Feb 2026 10:37:42 +0100 Subject: [PATCH 5/5] Fix point size and opacity dataset selection reset logic --- src/DatasetsAction.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/DatasetsAction.cpp b/src/DatasetsAction.cpp index 095442d..e77793e 100644 --- a/src/DatasetsAction.cpp +++ b/src/DatasetsAction.cpp @@ -28,6 +28,10 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : addAction(&_pointSizeDatasetPickerAction); addAction(&_pointOpacityDatasetPickerAction); + _colorDatasetPickerAction.setDefaultWidgetFlag(OptionAction::Clearable); + _pointSizeDatasetPickerAction.setDefaultWidgetFlag(OptionAction::Clearable); + _pointOpacityDatasetPickerAction.setDefaultWidgetFlag(OptionAction::Clearable); + _positionDatasetPickerAction.setFilterFunction([this](mv::Dataset dataset) -> bool { return dataset->getDataType() == PointType; }); @@ -56,9 +60,12 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : connect(&scatterplotPlugin->getPositionDataset(), &Dataset::changed, this, [this](DatasetImpl* dataset) -> void { _positionDatasetPickerAction.setCurrentDataset(dataset); }); - - connect(&_colorDatasetPickerAction, &DatasetPickerAction::datasetPicked, [this, scatterplotPlugin](Dataset pickedDataset) -> void { - scatterplotPlugin->getSettingsAction().getColoringAction().setCurrentColorDataset(pickedDataset); + + auto& coloringAction = scatterplotPlugin->getSettingsAction().getColoringAction(); + + connect(&_colorDatasetPickerAction, &DatasetPickerAction::datasetPicked, [this, &coloringAction](Dataset pickedDataset) -> void { + coloringAction.getColorByAction().setCurrentIndex(pickedDataset.isValid() ? 2 : 0); + coloringAction.setCurrentColorDataset(pickedDataset); }); connect(&scatterplotPlugin->getSettingsAction().getColoringAction(), &ColoringAction::currentColorDatasetChanged, this, [this](Dataset currentColorDataset) -> void { @@ -79,11 +86,11 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : connect(&pointSizeAction, &ScalarAction::sourceSelectionChanged, this, pointSizeSourceChanged); connect(&pointSizeAction, &ScalarAction::sourceDataChanged, this, pointSizeSourceChanged); - connect(&_pointSizeDatasetPickerAction, &DatasetPickerAction::datasetPicked, this, [this, &pointSizeAction](Dataset dataset) -> void { - if (!dataset.isValid()) - return; + connect(&_pointSizeDatasetPickerAction, &DatasetPickerAction::currentIndexChanged, this, [this, &pointSizeAction](const int32_t& currentIndex) -> void { + pointSizeAction.setCurrentDataset(_pointSizeDatasetPickerAction.getCurrentDataset()); - pointSizeAction.setCurrentDataset(dataset); + if (currentIndex < 0) + pointSizeAction.setCurrentSourceIndex(ScalarSourceModel::DefaultRow::Constant); }); const auto pointOpacitySourceChanged = [this, &pointOpacityAction]() -> void { @@ -96,11 +103,11 @@ DatasetsAction::DatasetsAction(QObject* parent, const QString& title) : connect(&pointOpacityAction, &ScalarAction::sourceSelectionChanged, this, pointOpacitySourceChanged); connect(&pointOpacityAction, &ScalarAction::sourceDataChanged, this, pointOpacitySourceChanged); - connect(&_pointOpacityDatasetPickerAction, &DatasetPickerAction::datasetPicked, this, [this, &pointOpacityAction](Dataset dataset) -> void { - if (!dataset.isValid()) - return; + connect(&_pointOpacityDatasetPickerAction, &DatasetPickerAction::currentIndexChanged, this, [this, &pointOpacityAction](const int32_t& currentIndex) -> void { + pointOpacityAction.setCurrentDataset(_pointOpacityDatasetPickerAction.getCurrentDataset()); - pointOpacityAction.setCurrentDataset(dataset); + if (currentIndex < 0) + pointOpacityAction.setCurrentSourceIndex(ScalarSourceModel::DefaultRow::Constant); }); }