Tulip  5.4.0
Large graphs analysis and drawing
interactor_plugin/interactor_plugin.cpp

This example gives a minimalistic approach of interaction with a graph In this example, we are making an interactor plugin for Node link diagram view that will activate zoom and pan and display information when you click on a node/edge.

The code contains a step-by-step explanation of the process, please refer to classes documentation for more information about their usage.

#include <QPropertyAnimation>
#include <QGraphicsView>
#include <QLabel>
#include <QGraphicsProxyWidget>
#include <tulip/MouseInteractors.h>
#include <tulip/Interactor.h>
#include <tulip/GlMainView.h>
#include <tulip/GlMainWidget.h>
#include <tulip/GlScene.h>
using namespace tlp;
/*
In this class we create an GLInteractorComponent
In first see InteractorPlugin
*/
class InteractorPluginComponent : public InteractorComponent {
QGraphicsProxyWidget *_informationWidgetItem;
QLabel *_informationLabel;
public:
/*
Basic constructor
In this constructor we create a label to display information
And a QGraphicsProxyWidget to show information in Tulip QGraphics system
*/
InteractorPluginComponent() {
_informationLabel = new QLabel();
_informationWidgetItem = new QGraphicsProxyWidget();
_informationWidgetItem->setWidget(_informationLabel);
_informationWidgetItem->setVisible(false);
}
/*
This function is call when the view associated to this interactor is changed
So at this moment we add information QGraphicsItem to the QGraphicsScene
*/
void viewChanged(View *view) {
view->graphicsView()->scene()->addItem(_informationWidgetItem);
}
/*
Most important function of an interactor component
When an event arrive on your interactor : this function is call
You have to process it and return true. If the event do nothing in your interactor : this function
return false;
*/
bool eventFilter(QObject *, QEvent *e) {
/*
If you have clicked on a node/edge, information widget is visible.
And if you use the wheel of the mouse we hide the information widget
*/
if (_informationWidgetItem->isVisible() && e->type() == QEvent::Wheel) {
_informationWidgetItem->setVisible(false);
return false;
}
/*
Check if the event is a mouse event
*/
QMouseEvent *qMouseEv = dynamic_cast<QMouseEvent *>(e);
if (qMouseEv != nullptr) {
GlMainView *glMainView = static_cast<GlMainView *>(view());
/*
Check if event is a left mouse button press
*/
if (e->type() == QEvent::MouseButtonPress && qMouseEv->button() == Qt::LeftButton) {
/*
If you have clicked on a node/edge, information widget is visible.
And if you reclick : hide it
*/
if (_informationWidgetItem->isVisible()) {
_informationWidgetItem->setVisible(false);
} else {
/*
Select entities under the mouse cursor
The result of selection is stored in SelectedEntity
And pickNodesEdges return true if you click on node or edge
*/
SelectedEntity selectedEntity;
if (glMainView->getGlMainWidget()->pickNodesEdges(qMouseEv->x(), qMouseEv->y(),
selectedEntity)) {
/*
Change text of the information label with
- If you click on a node : "Click on node id : nodeId"
- If you click on an edge : "Click on edge id : edgeId"
*/
QString text("Click on ");
if (selectedEntity.getEntityType() == SelectedEntity::NODE_SELECTED)
text += "node ";
else
text += "edge ";
text += " id : " + QString::number(selectedEntity.getComplexEntityId());
/*
- Update QLabel with new text
- Auto resize QLabel
- Set position of the label at mouse position
- Display it
*/
_informationLabel->setText(text);
_informationLabel->adjustSize();
_informationWidgetItem->setPos(qMouseEv->pos());
_informationWidgetItem->setVisible(true);
/*
Here we just add a small smooth animation on the label pop
*/
QPropertyAnimation *animation =
new QPropertyAnimation(_informationWidgetItem, "opacity");
animation->setDuration(100);
animation->setStartValue(0.);
animation->setEndValue(0.99);
animation->start();
/*
We have treated the event so we return true
*/
return true;
}
}
}
}
/*
We don't have treated the event se we return false
*/
return false;
}
};
/*
If you want to create an interactor plugin, the first think to do is to create a sub class of
InteractorComposite
*/
class InteractorPlugin : public InteractorComposite {
QLabel *_configurationLabel;
public:
/*
This macro is here to register information about the plugin
PLUGININFORMATION(Plugin name, Author, Date, Plugin long name, version, type of plugin
(Navigation,Information...))
*/
PLUGININFORMATION("InteractorPlugin", "Tulip Team", "05/10/2012", "Demo Interactor", "1.0",
"Information")
/*
The constructor
Here we specify the icon of interactor with Qt qrc system, and the ToolTip text of the plugin
*/
InteractorPlugin(const tlp::PluginContext *)
: InteractorComposite(QIcon(":/i_interactor_plugin.png"), "Demo Interactor") {
/*
Here we create a label with a minimal configuration text
This text will be displayed when you click on the name of the plugin
*/
_configurationLabel =
new QLabel(QString("This is a demo interactor.<br>") +
"You can zoom and pan and display information if you click on a node/edge.");
}
~InteractorPlugin() {
delete _configurationLabel;
}
/*
Here we construct the interactor
An InteractorComposite is a list of InteractorComponent.
It's like a chain of responsibility :
- When an event arrive the first InteractorComponent catch it in eventFilter function.
- If the InteractorComponent don't process this event (if eventFilter function return false), the
event is passed to the second InteractorComponent
In this example we have two InteractorComponent
The first one : InteractorPluginComponent is the example InteractorComponent
The second one : MouseNKeysNavigation is a standard Tulip InteractorComponent who activate Zoom
and pan interaction
*/
void construct() {
push_back(new MouseNKeysNavigator);
push_back(new InteractorPluginComponent);
}
/*
In this function we say : this plugin is compatible with Node Link Diagram View
If you don't implement this function your plugin won't be displayed in interactors tool bar
*/
bool isCompatible(const std::string &viewName) const {
return (viewName == "Node Link Diagram view");
}
/*
In this function we say : _configurationLabel is the configuration widget
*/
QWidget *configurationWidget() const {
return _configurationLabel;
}
/*
In Plugin system we have a priority system to display interactor icon
If priority is low, you interactor will be at the left of the interactord tool bar
*/
unsigned int priority() const {
return 5;
}
};
/*
With this macro you register your plugin in Tulip plugin engine
*/
PLUGIN(InteractorPlugin)