Skip to content

Commit e57d352

Browse files
committed
added 'hover over node' feature in dot viewer
1 parent f4f03cd commit e57d352

File tree

9 files changed

+111
-36
lines changed

9 files changed

+111
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
88
* simulation
99
* added feature, selecting a waveform in viewer selects net in graph view as well
1010
* fixed bug in waveform viewer, make sure that deleting a controller causes closing the tab
11+
* added 'hover over node' feature in dot viewer
1112
* fixed broken initialization of DANA plugin when starting via CLI
1213
* changed behavior of GUI plugin manager to keep only those plugins loaded which are requested by user
1314
* fixed bug in the bitorder propagation algorithm that would assign a wrong propagation order if pingroups with direction none were given as parameters

plugins/dot_viewer/deps/QGVCore/QGVEdge.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ License along with this library.
2323
#include <QDebug>
2424
#include <QPainter>
2525

26-
QGVEdge::QGVEdge(QGVEdgePrivate *edge, QGVScene *scene) : _scene(scene), _edge(edge), _head_node(nullptr), _tail_node(nullptr)
26+
QGVEdge::QGVEdge(QGVEdgePrivate *edge, QGVScene *scene) : _scene(scene), _edge(edge), _head_node(nullptr), _tail_node(nullptr), mHover(false)
2727
{
2828
setFlag(QGraphicsItem::ItemIsSelectable, true);
2929
}
@@ -44,12 +44,14 @@ QRectF QGVEdge::boundingRect() const
4444
return _path.boundingRect() | _head_arrow.boundingRect() | _tail_arrow.boundingRect() | _label_rect;
4545
}
4646

47-
void QGVEdge::setEndpoints(const QHash<void*,QGVNode*>& nodeHash)
47+
void QGVEdge::setEndpoints(const QHash<void *, QGVNode *> &nodeHash, QMultiMap<QGVNode *, QGVEdge *>& attachedEdges)
4848
{
4949
auto agHead = _edge->endpoint(true);
5050
if (agHead) _head_node = nodeHash.value(agHead, nullptr);
51+
attachedEdges.insert(_head_node, this);
5152
auto agTail = _edge->endpoint(false);
5253
if (agTail) _tail_node = nodeHash.value(agTail, nullptr);
54+
attachedEdges.insert(_tail_node, this);
5355
}
5456

5557
QGVNode* QGVEdge::headNode() const
@@ -82,6 +84,12 @@ void QGVEdge::setHightlight(const QString& hilight)
8284
update();
8385
}
8486

87+
void QGVEdge::setHover(bool hover)
88+
{
89+
mHover = hover;
90+
update();
91+
}
92+
8593
void QGVEdge::paintText(QPainter* painter)
8694
{
8795
int pos = _highlight_text.isEmpty() ? -1 : _label.indexOf(_highlight_text);
@@ -106,15 +114,15 @@ void QGVEdge::paintText(QPainter* painter)
106114
if (count % 2 > 0)
107115
{
108116
// highlight
109-
tpen.setColor(QGVStyle::instance()->penColor(true,_pen.color()));
117+
tpen.setColor(QGVStyle::instance()->penColor(true,mHover,_pen.color()));
110118
lastPos = pos + _highlight_text.size();
111119
part = _label.mid(pos, lastPos-pos);
112120
pos = _label.indexOf(_highlight_text, lastPos);
113121
}
114122
else
115123
{
116124
// normal
117-
tpen.setColor(QGVStyle::instance()->penColor(false,_pen.color()));
125+
tpen.setColor(QGVStyle::instance()->penColor(false,mHover,_pen.color()));
118126
int len = pos < 0 ? _label.size() - lastPos : pos - lastPos;
119127
if (len > 0) part = _label.mid(lastPos,len);
120128
}
@@ -134,7 +142,7 @@ void QGVEdge::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidge
134142
painter->save();
135143

136144
QPen tpen(_pen);
137-
tpen.setColor(QGVStyle::instance()->penColor(isSelected(),_pen.color()));
145+
tpen.setColor(QGVStyle::instance()->penColor(isSelected(),mHover,_pen.color()));
138146
tpen.setWidth(isSelected() ? 2 : 1);
139147
painter->setPen(tpen);
140148

plugins/dot_viewer/deps/QGVCore/QGVEdge.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ class QGVCORE_EXPORT QGVEdge : public QGraphicsItem
4848

4949
void updateLayout();
5050

51-
void setEndpoints(const QHash<void*,QGVNode*>& nodeHash);
51+
void setEndpoints(const QHash<void*, QGVNode*>& nodeHash, QMultiMap<QGVNode*, QGVEdge*>& attachedEdges);
5252

5353
void setHightlight(const QString& hilight);
5454

55+
void setHover(bool hover);
56+
5557
QGVNode* headNode() const;
5658
QGVNode* tailNode() const;
5759

@@ -86,6 +88,8 @@ class QGVCORE_EXPORT QGVEdge : public QGraphicsItem
8688
QGVNode* _tail_node;
8789

8890
QString _highlight_text;
91+
92+
bool mHover;
8993
};
9094

9195
#endif // QGVEDGE_H

plugins/dot_viewer/deps/QGVCore/QGVNode.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ License along with this library.
2323
#include <QDebug>
2424
#include <QPainter>
2525

26-
QGVNode::QGVNode(QGVNodePrivate *node, QGVScene *scene): _scene(scene), _node(node)
26+
QGVNode::QGVNode(QGVNodePrivate *node, QGVScene *scene): _scene(scene), _node(node), mHover(false)
2727
{
28+
setAcceptHoverEvents(true);
2829
setFlag(QGraphicsItem::ItemIsSelectable, true);
2930
}
3031

@@ -55,12 +56,28 @@ QRectF QGVNode::boundingRect() const
5556
return _path.boundingRect();
5657
}
5758

59+
void QGVNode::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
60+
{
61+
Q_UNUSED(event);
62+
mHover = true;
63+
_scene->hoverEnterEdges(this);
64+
update();
65+
}
66+
67+
void QGVNode::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
68+
{
69+
Q_UNUSED(event);
70+
mHover = false;
71+
_scene->hoverLeaveEdges();
72+
update();
73+
}
74+
5875
void QGVNode::paint(QPainter * painter, const QStyleOptionGraphicsItem *, QWidget *)
5976
{
6077
painter->save();
6178

6279
painter->setPen(_pen);
63-
painter->setBrush(QGVStyle::instance()->nodeBrush(isSelected(), _brush));
80+
painter->setBrush(QGVStyle::instance()->nodeBrush(isSelected(), mHover, _brush));
6481
painter->drawPath(_path);
6582

6683
painter->setPen(QGVCore::toColor(getAttribute("labelfontcolor")));

plugins/dot_viewer/deps/QGVCore/QGVNode.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,24 @@ class QGVCORE_EXPORT QGVNode : public QGraphicsItem
3838
QString label() const;
3939
void setLabel(const QString &label);
4040

41-
QRectF boundingRect() const;
42-
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
41+
QRectF boundingRect() const override;
42+
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0) override;
4343
void setAttribute(const QString &label, const QString &value);
4444
QString getAttribute(const QString &name) const;
4545

4646
void setIcon(const QImage &icon);
4747
QString getShape() const;
4848

4949
enum { Type = UserType + 2 };
50-
int type() const
50+
int type() const override
5151
{
5252
return Type;
5353
}
5454

55+
protected:
56+
void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
57+
void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
58+
5559
private:
5660
friend class QGVScene;
5761
friend class QGVSubGraph;
@@ -69,6 +73,7 @@ class QGVCORE_EXPORT QGVNode : public QGraphicsItem
6973

7074
QGVScene *_scene;
7175
QGVNodePrivate* _node;
76+
bool mHover;
7277
};
7378

7479

plugins/dot_viewer/deps/QGVCore/QGVScene.cpp

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ QGVNode *QGVScene::addNode(const QString &label)
116116
QGVNode *item = new QGVNode(new QGVNodePrivate(node, _graph->graph()), this);
117117
item->setLabel(label);
118118
addItem(item);
119-
_nodes.append(item);
119+
mNodes.append(item);
120120
return item;
121121
}
122122

@@ -132,7 +132,7 @@ QGVEdge *QGVScene::addEdge(QGVNode *source, QGVNode *target, const QString &labe
132132
QGVEdge *item = new QGVEdge(new QGVEdgePrivate(edge), this);
133133
item->setLabel(label);
134134
addItem(item);
135-
_edges.append(item);
135+
mEdges.append(item);
136136
return item;
137137
}
138138

@@ -158,27 +158,36 @@ QGVSubGraph *QGVScene::addSubGraph(const QString &name, bool cluster)
158158

159159
void QGVScene::deleteNode(QGVNode* node)
160160
{
161-
QList<QGVNode *>::iterator it = std::find(_nodes.begin(), _nodes.end(), node);
162-
if(it == _nodes.end())
161+
QList<QGVNode *>::iterator it = std::find(mNodes.begin(), mNodes.end(), node);
162+
if(it == mNodes.end())
163163
{
164164
std::cout << "Error, node not part of Scene" << std::endl;
165165
return;
166166
}
167167
std::cout << "delNode ret " << agdelnode(node->_node->graph(), node->_node->node()) << std::endl;;
168-
_nodes.erase(it);
168+
auto jt = mAttachedEdges.lowerBound(node);
169+
while (jt != mAttachedEdges.upperBound(node))
170+
jt = mAttachedEdges.erase(jt);
171+
mNodes.erase(it);
169172
delete node;
170173
}
171174

172175
void QGVScene::deleteEdge(QGVEdge* edge)
173176
{
174177
std::cout << "delEdge ret " << agdeledge(_graph->graph(), edge->_edge->edge()) << std::endl;
175-
QList<QGVEdge *>::iterator it = std::find(_edges.begin(), _edges.end(), edge);
176-
if(it == _edges.end())
178+
QList<QGVEdge *>::iterator it = std::find(mEdges.begin(), mEdges.end(), edge);
179+
if(it == mEdges.end())
177180
{
178181
std::cout << "Error, QGVEdge not part of Scene" << std::endl;
179182
return;
180183
}
181-
_edges.erase(it);
184+
auto jt = mAttachedEdges.begin();
185+
while (jt != mAttachedEdges.end())
186+
if (jt.value() == edge)
187+
jt = mAttachedEdges.erase(jt);
188+
else
189+
++jt;
190+
mEdges.erase(it);
182191
delete edge;
183192
}
184193

@@ -199,7 +208,7 @@ void QGVScene::deleteSubGraph(QGVSubGraph *subgraph)
199208

200209
void QGVScene::setRootNode(QGVNode *node)
201210
{
202-
Q_ASSERT(_nodes.contains(node));
211+
Q_ASSERT(mNodes.contains(node));
203212
char root[] = "root";
204213
agset(_graph->graph(), root, node->label().toLocal8Bit().data());
205214
}
@@ -225,8 +234,10 @@ void QGVScene::loadLayout(const QString &text, QGVInteraction *interact)
225234
//Debug output
226235
//gvRenderFilename(_context->context(), _graph->graph(), "png", "debug.png");
227236

237+
mAttachedEdges.clear();
238+
mNodes.clear();
239+
mEdges.clear();
228240
QHash<void*, QGVNode*> nodeHash;
229-
QList<QGVEdge*> edgeList;
230241

231242
//Read nodes and edges
232243
for (Agnode_t* node = agfstnode(_graph->graph()); node != NULL; node = agnxtnode(_graph->graph(), node))
@@ -236,18 +247,19 @@ void QGVScene::loadLayout(const QString &text, QGVInteraction *interact)
236247
inode->updateLayout();
237248
addItem(inode);
238249
nodeHash[node] = inode;
250+
mNodes.append(inode);
239251
for (Agedge_t* edge = agfstout(_graph->graph(), node); edge != NULL; edge = agnxtout(_graph->graph(), edge))
240252
{
241253
QGVEdge *iedge = new QGVEdge(new QGVEdgePrivate(edge), this);
242254
if (interact) interact->registerEdge(iedge);
243255
iedge->updateLayout();
244256
addItem(iedge);
245-
edgeList.append(iedge);
257+
mEdges.append(iedge);
246258
}
247259
}
248260

249-
for (QGVEdge* iedge : edgeList)
250-
iedge->setEndpoints(nodeHash);
261+
for (QGVEdge* iedge : mEdges)
262+
iedge->setEndpoints(nodeHash, mAttachedEdges);
251263

252264
update();
253265
/*
@@ -277,10 +289,10 @@ void QGVScene::applyLayout()
277289
//gvRenderFilename(_context->context(), _graph->graph(), "png", "debug.png");
278290

279291
//Update items layout
280-
foreach(QGVNode* node, _nodes)
292+
foreach(QGVNode* node, mNodes)
281293
node->updateLayout();
282294

283-
foreach(QGVEdge* edge, _edges)
295+
foreach(QGVEdge* edge, mEdges)
284296
edge->updateLayout();
285297

286298
foreach(QGVSubGraph* sgraph, _subGraphs)
@@ -299,11 +311,24 @@ void QGVScene::applyLayout()
299311
update();
300312
}
301313

314+
void QGVScene::hoverEnterEdges(QGVNode* node)
315+
{
316+
for (auto it = mAttachedEdges.lowerBound(node); it != mAttachedEdges.upperBound(node); ++it)
317+
it.value()->setHover(true);
318+
}
319+
320+
void QGVScene::hoverLeaveEdges()
321+
{
322+
for (QGVEdge* edge : mEdges)
323+
edge->setHover(false);
324+
}
325+
326+
302327
void QGVScene::clear()
303328
{
304329
gvFreeLayout(_context->context(), _graph->graph());
305-
_nodes.clear();
306-
_edges.clear();
330+
mNodes.clear();
331+
mEdges.clear();
307332
_subGraphs.clear();
308333
QGraphicsScene::clear();
309334
}
@@ -417,17 +442,20 @@ void QGVStyle::changeHalStyle(StyleType type)
417442
}
418443
}
419444

420-
QColor QGVStyle::penColor(bool selected, const QColor& graphvizColor) const
445+
QColor QGVStyle::penColor(bool selected, bool hovered, const QColor& graphvizColor) const
421446
{
422447
switch (mStyleType[EdgeStyle]) {
423448
case Dark:
424449
if (selected) return QColor(Qt::cyan);
450+
if (hovered) return QColor::fromRgb(255,200,200);
425451
return QColor::fromRgb(200,200,200);
426452
case Light:
427453
if (selected) return QColor(Qt::blue);
454+
if (hovered) return QColor(Qt::darkRed);
428455
return QColor(Qt::black);
429456
case Graphviz:
430457
if (selected) return graphvizColor.darker(120);
458+
if (hovered) return graphvizColor.darker(110);
431459
return graphvizColor;
432460
}
433461
return QColor();
@@ -460,17 +488,20 @@ QColor QGVStyle::gridColor() const
460488
}
461489

462490

463-
QBrush QGVStyle::nodeBrush(bool selected, const QBrush& graphvizBrush) const
491+
QBrush QGVStyle::nodeBrush(bool selected, bool hovered, const QBrush& graphvizBrush) const
464492
{
465493
switch (mStyleType[NodeStyle]) {
466494
case Dark:
467495
if (selected) return QBrush(Qt::white);
496+
if (hovered) return QBrush(QColor::fromRgb(255,200,200));
468497
return QBrush(QColor::fromRgb(160,161,164));
469498
case Light:
470499
if (selected) return QBrush(QColor::fromRgb(220,221,223));
500+
if (hovered) return QBrush(QColor::fromRgb(220,221,255));
471501
return QBrush(Qt::white);
472502
case Graphviz:
473503
if (selected) return QBrush(graphvizBrush.color().darker(120));
504+
if (hovered) return QBrush(graphvizBrush.color().darker(110));
474505
return graphvizBrush;
475506
}
476507
return QBrush();

plugins/dot_viewer/deps/QGVCore/QGVScene.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ License along with this library.
2424
#include <QBrush>
2525
#include <QHash>
2626
#include <QString>
27+
#include <QMultiMap>
2728

2829
class QGVNode;
2930
class QGVEdge;
@@ -50,10 +51,10 @@ class QGVStyle
5051
void changeHalStyle(StyleType type);
5152
StyleType getStyle(StyleTarget target) const;
5253

53-
QColor penColor(bool selected, const QColor& graphvizColor) const;
54+
QColor penColor(bool selected, bool hovered, const QColor& graphvizColor) const;
5455
QColor gridColor() const;
5556
QColor selectFrameColor() const;
56-
QBrush nodeBrush(bool selected, const QBrush& graphvizBrush) const;
57+
QBrush nodeBrush(bool selected, bool hovered, const QBrush& graphvizBrush) const;
5758
private:
5859
StyleType mStyleType[2];
5960
};
@@ -137,10 +138,14 @@ public Q_SLOTS:
137138
QGVGraphPrivate *_graph;
138139
//QFont _font;
139140

140-
QList<QGVNode*> _nodes;
141-
QList<QGVEdge*> _edges;
141+
QList<QGVNode*> mNodes;
142+
QList<QGVEdge*> mEdges;
142143
QList<QGVSubGraph*> _subGraphs;
143144

145+
QMultiMap<QGVNode*,QGVEdge*> mAttachedEdges;
146+
void hoverEnterEdges(QGVNode* node);
147+
void hoverLeaveEdges();
148+
144149
bool _drawGrid;
145150

146151
static int sCount;

0 commit comments

Comments
 (0)