diff --git a/CMakeLists.txt b/CMakeLists.txt index a54b9f1..a8d0d4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,3 +14,4 @@ add_subdirectory(ExampleTransformation) add_subdirectory(ExampleLoader) add_subdirectory(ExampleWriter) add_subdirectory(ExampleData) +add_subdirectory(ExampleActions) diff --git a/ExampleActions/CMakeLists.txt b/ExampleActions/CMakeLists.txt index fd41640..8c90631 100644 --- a/ExampleActions/CMakeLists.txt +++ b/ExampleActions/CMakeLists.txt @@ -5,7 +5,7 @@ option(MV_UNITY_BUILD "Combine target source files into batches for faster compi # ----------------------------------------------------------------------------- # ExampleView Plugin # ----------------------------------------------------------------------------- -PROJECT("ExampleViewPlugin") +PROJECT("ExampleActionsPlugin") # ----------------------------------------------------------------------------- # CMake Options @@ -41,13 +41,13 @@ find_package(Qt6 COMPONENTS Widgets WebEngineWidgets REQUIRED) # ----------------------------------------------------------------------------- # Define the plugin sources set(PLUGIN_SOURCES - src/ExampleViewPlugin.h - src/ExampleViewPlugin.cpp - src/ExampleViewPlugin.json + src/ExampleActionsPlugin.h + src/ExampleActionsPlugin.cpp + src/ExampleActionsPlugin.json ) set(PLUGIN_MOC_HEADERS - src/ExampleViewPlugin.h + src/ExampleActionsPlugin.h ) source_group( Plugin FILES ${PLUGIN_SOURCES}) diff --git a/ExampleActions/src/ExampleActionsPlugin.cpp b/ExampleActions/src/ExampleActionsPlugin.cpp new file mode 100644 index 0000000..76ef38f --- /dev/null +++ b/ExampleActions/src/ExampleActionsPlugin.cpp @@ -0,0 +1,30 @@ +#include "ExampleActionsPlugin.h" + +#include + +#include + +Q_PLUGIN_METADATA(IID "studio.manivault.ExampleActionsPlugin") + +using namespace mv; + +ExampleActionsPlugin::ExampleActionsPlugin(const PluginFactory* factory) : + ViewPlugin(factory) +{ +} + +void ExampleActionsPlugin::init() +{ + // Create layout + auto layout = new QVBoxLayout(); + + layout->setContentsMargins(0, 0, 0, 0); + + // Apply the layout + getWidget().setLayout(layout); +} + +ViewPlugin* ExampleActionsPluginFactory::produce() +{ + return new ExampleActionsPlugin(this); +} diff --git a/ExampleActions/src/ExampleActionsPlugin.h b/ExampleActions/src/ExampleActionsPlugin.h new file mode 100644 index 0000000..177ad13 --- /dev/null +++ b/ExampleActions/src/ExampleActionsPlugin.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include + +/** All plugin related classes are in the ManiVault plugin namespace */ +using namespace mv::plugin; + +/** Drop widget used in this plugin is located in the ManiVault gui namespace */ +using namespace mv::gui; + +/** Dataset reference used in this plugin is located in the ManiVault util namespace */ +using namespace mv::util; + +/** + * Example actions view plugin class + * + * This view plugin class provides skeleton code that shows how to use GUI building + * blocks (aka actions) to build interfaces. + * + * To see the plugin in action, please follow the steps below: + * + * 1. Go to the visualization menu in ManiVault + * 2. Choose the Example actions menu item, the view will be added to the layout + * + * @author T. Kroes + */ +class ExampleActionsPlugin : public ViewPlugin +{ + Q_OBJECT + +public: + + /** + * Construct with pointer to plugin \p factory + * @param factory Pointer to the plugin factory + */ + ExampleActionsPlugin(const PluginFactory* factory); + + /** Destructor */ + ~ExampleActionsPlugin() override = default; + + /** This function is called by the core after the view plugin has been created */ + void init() override; +}; + +/** + * Example actions plugin factory class + * + * Note: Factory does not need to be altered (merely responsible for generating new plugins when requested) + */ +class ExampleActionsPluginFactory : public ViewPluginFactory +{ + Q_INTERFACES(mv::plugin::ViewPluginFactory mv::plugin::PluginFactory) + Q_OBJECT + Q_PLUGIN_METADATA(IID "studio.manivault.ExampleActionsPlugin" + FILE "ExampleActionsPlugin.json") + +public: + + /** Default constructor */ + ExampleActionsPluginFactory() {} + + /** Destructor */ + ~ExampleActionsPluginFactory() override {} + + /** Creates an instance of the example view plugin */ + ViewPlugin* produce() override; +}; diff --git a/ExampleActions/src/ExampleViewPlugin.json b/ExampleActions/src/ExampleActionsPlugin.json similarity index 64% rename from ExampleActions/src/ExampleViewPlugin.json rename to ExampleActions/src/ExampleActionsPlugin.json index a967080..dffc5ec 100644 --- a/ExampleActions/src/ExampleViewPlugin.json +++ b/ExampleActions/src/ExampleActionsPlugin.json @@ -1,5 +1,5 @@ { - "name" : "Example View", + "name" : "Example Actions", "version" : "1.1", "dependencies" : ["Points"] } diff --git a/ExampleActions/src/ExampleViewPlugin.cpp b/ExampleActions/src/ExampleViewPlugin.cpp deleted file mode 100644 index 0c5732a..0000000 --- a/ExampleActions/src/ExampleViewPlugin.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "ExampleViewPlugin.h" - -#include - -#include - -#include -#include - -Q_PLUGIN_METADATA(IID "studio.manivault.ExampleViewPlugin") - -using namespace mv; - -ExampleViewPlugin::ExampleViewPlugin(const PluginFactory* factory) : - ViewPlugin(factory), - _dropWidget(nullptr), - _points(), - _currentDatasetName(), - _currentDatasetNameLabel(new QLabel()) -{ - // This line is mandatory if drag and drop behavior is required - _currentDatasetNameLabel->setAcceptDrops(true); - - // Align text in the center - _currentDatasetNameLabel->setAlignment(Qt::AlignCenter); -} - -void ExampleViewPlugin::init() -{ - // Create layout - auto layout = new QVBoxLayout(); - - layout->setContentsMargins(0, 0, 0, 0); - - layout->addWidget(_currentDatasetNameLabel); - - // Apply the layout - getWidget().setLayout(layout); - - // Instantiate new drop widget - _dropWidget = new DropWidget(_currentDatasetNameLabel); - - // Set the drop indicator widget (the widget that indicates that the view is eligible for data dropping) - _dropWidget->setDropIndicatorWidget(new DropWidget::DropIndicatorWidget(&getWidget(), "No data loaded", "Drag an item from the data hierarchy and drop it here to visualize data...")); - - // Initialize the drop regions - _dropWidget->initialize([this](const QMimeData* mimeData) -> DropWidget::DropRegions { - // A drop widget can contain zero or more drop regions - DropWidget::DropRegions dropRegions; - - const auto datasetsMimeData = dynamic_cast(mimeData); - - if (datasetsMimeData == nullptr) - return dropRegions; - - if (datasetsMimeData->getDatasets().count() > 1) - return dropRegions; - - // Gather information to generate appropriate drop regions - const auto dataset = datasetsMimeData->getDatasets().first(); - const auto datasetGuiName = dataset->getGuiName(); - const auto datasetId = dataset->getId(); - const auto dataType = dataset->getDataType(); - const auto dataTypes = DataTypes({ PointType }); - - // Visually indicate if the dataset is of the wrong data type and thus cannot be dropped - if (!dataTypes.contains(dataType)) { - dropRegions << new DropWidget::DropRegion(this, "Incompatible data", "This type of data is not supported", "exclamation-circle", false); - } - else { - - // Get points dataset from the core - auto candidateDataset = mv::data().getDataset(datasetId); - - // Accept points datasets drag and drop - if (dataType == PointType) { - const auto description = QString("Load %1 into example view").arg(datasetGuiName); - - if (_points == candidateDataset) { - - // Dataset cannot be dropped because it is already loaded - dropRegions << new DropWidget::DropRegion(this, "Warning", "Data already loaded", "exclamation-circle", false); - } - else { - - // Dataset can be dropped - dropRegions << new DropWidget::DropRegion(this, "Points", description, "map-marker-alt", true, [this, candidateDataset]() { - _points = candidateDataset; - }); - } - } - } - - return dropRegions; - }); - - // Respond when the name of the dataset in the dataset reference changes - connect(&_points, &Dataset::guiNameChanged, this, [this]() { - - auto newDatasetName = _points->getGuiName(); - - // Update the current dataset name label - _currentDatasetNameLabel->setText(QString("Current points dataset: %1").arg(newDatasetName)); - - // Only show the drop indicator when nothing is loaded in the dataset reference - _dropWidget->setShowDropIndicator(newDatasetName.isEmpty()); - }); - - // Alternatively, classes which derive from hdsp::EventListener (all plugins do) can also respond to events - _eventListener.addSupportedEventType(static_cast(EventType::DatasetAdded)); - _eventListener.addSupportedEventType(static_cast(EventType::DatasetDataChanged)); - _eventListener.addSupportedEventType(static_cast(EventType::DatasetRemoved)); - _eventListener.addSupportedEventType(static_cast(EventType::DatasetDataSelectionChanged)); - _eventListener.registerDataEventByType(PointType, std::bind(&ExampleViewPlugin::onDataEvent, this, std::placeholders::_1)); -} - -void ExampleViewPlugin::onDataEvent(mv::DatasetEvent* dataEvent) -{ - // Get smart pointer to dataset that changed - const auto changedDataSet = dataEvent->getDataset(); - - // Get GUI name of the dataset that changed - const auto datasetGuiName = changedDataSet->getGuiName(); - - // The data event has a type so that we know what type of data event occurred (e.g. data added, changed, removed, renamed, selection changes) - switch (dataEvent->getType()) { - - // A points dataset was added - case EventType::DatasetAdded: - { - // Cast the data event to a data added event - const auto dataAddedEvent = static_cast(dataEvent); - - // Get the GUI name of the added points dataset and print to the console - qDebug() << datasetGuiName << "was added"; - - break; - } - - // Points dataset data has changed - case EventType::DatasetDataChanged: - { - // Cast the data event to a data changed event - const auto dataChangedEvent = static_cast(dataEvent); - - // Get the name of the points dataset of which the data changed and print to the console - qDebug() << datasetGuiName << "data changed"; - - break; - } - - // Points dataset data was removed - case EventType::DatasetRemoved: - { - // Cast the data event to a data removed event - const auto dataRemovedEvent = static_cast(dataEvent); - - // Get the name of the removed points dataset and print to the console - qDebug() << datasetGuiName << "was removed"; - - break; - } - - // Points dataset selection has changed - case EventType::DatasetDataSelectionChanged: - { - // Cast the data event to a data selection changed event - const auto dataSelectionChangedEvent = static_cast(dataEvent); - - // Get the selection set that changed - const auto& selectionSet = changedDataSet->getSelection(); - - // Print to the console - qDebug() << datasetGuiName << "selection has changed"; - - break; - } - - default: - break; - } -} - -ViewPlugin* ExampleViewPluginFactory::produce() -{ - return new ExampleViewPlugin(this); -} - -mv::DataTypes ExampleViewPluginFactory::supportedDataTypes() const -{ - DataTypes supportedTypes; - - // This example analysis plugin is compatible with points datasets - supportedTypes.append(PointType); - - return supportedTypes; -} - -mv::gui::PluginTriggerActions ExampleViewPluginFactory::getPluginTriggerActions(const mv::Datasets& datasets) const -{ - PluginTriggerActions pluginTriggerActions; - - const auto getPluginInstance = [this]() -> ExampleViewPlugin* { - return dynamic_cast(plugins().requestViewPlugin(getKind())); - }; - - const auto numberOfDatasets = datasets.count(); - - if (numberOfDatasets >= 1 && PluginFactory::areAllDatasetsOfTheSameType(datasets, PointType)) { - auto pluginTriggerAction = new PluginTriggerAction(const_cast(this), this, "Example", "View example data", getIcon(), [this, getPluginInstance, datasets](PluginTriggerAction& pluginTriggerAction) -> void { - for (auto dataset : datasets) - getPluginInstance(); - }); - - pluginTriggerActions << pluginTriggerAction; - } - - return pluginTriggerActions; -} diff --git a/ExampleActions/src/ExampleViewPlugin.h b/ExampleActions/src/ExampleViewPlugin.h deleted file mode 100644 index 84dcd33..0000000 --- a/ExampleActions/src/ExampleViewPlugin.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include - -#include - -/** All plugin related classes are in the ManiVault plugin namespace */ -using namespace mv::plugin; - -/** Drop widget used in this plugin is located in the ManiVault gui namespace */ -using namespace mv::gui; - -/** Dataset reference used in this plugin is located in the ManiVault util namespace */ -using namespace mv::util; - -class QLabel; - -/** - * Example view plugin class - * - * This view plugin class provides skeleton code that shows how to develop - * a view plugin in ManiVault. It shows how to use the built-in drag and drop - * behavior. - * - * To see the plugin in action, please follow the steps below: - * - * 1. Go to the visualization menu in ManiVault - * 2. Choose the Example view menu item, the view will be added to the layout - * - * @authors J. Thijssen & T. Kroes - */ -class ExampleViewPlugin : public ViewPlugin -{ - Q_OBJECT - -public: - - /** - * Constructor - * @param factory Pointer to the plugin factory - */ - ExampleViewPlugin(const PluginFactory* factory); - - /** Destructor */ - ~ExampleViewPlugin() override = default; - - /** This function is called by the core after the view plugin has been created */ - void init() override; - - /** - * Invoked when a data event occurs - * @param dataEvent Data event which occurred - */ - void onDataEvent(mv::DatasetEvent* dataEvent); - -protected: - DropWidget* _dropWidget; /** Widget for drag and drop behavior */ - mv::Dataset _points; /** Points smart pointer */ - QString _currentDatasetName; /** Name of the current dataset */ - QLabel* _currentDatasetNameLabel; /** Label that show the current dataset name */ -}; - -/** - * Example view plugin factory class - * - * Note: Factory does not need to be altered (merely responsible for generating new plugins when requested) - */ -class ExampleViewPluginFactory : public ViewPluginFactory -{ - Q_INTERFACES(mv::plugin::ViewPluginFactory mv::plugin::PluginFactory) - Q_OBJECT - Q_PLUGIN_METADATA(IID "studio.manivault.ExampleViewPlugin" - FILE "ExampleViewPlugin.json") - -public: - - /** Default constructor */ - ExampleViewPluginFactory() {} - - /** Destructor */ - ~ExampleViewPluginFactory() override {} - - /** Creates an instance of the example view plugin */ - ViewPlugin* produce() override; - - /** Returns the data types that are supported by the example view plugin */ - mv::DataTypes supportedDataTypes() const override; - - /** - * Get plugin trigger actions given \p datasets - * @param datasets Vector of input datasets - * @return Vector of plugin trigger actions - */ - PluginTriggerActions getPluginTriggerActions(const mv::Datasets& datasets) const override; -};