31 #include <QWheelEvent>
32 #include <QGraphicsSceneMouseEvent>
37 QY2Graph::QY2Graph(
const std::string& filename,
const std::string& layoutAlgorithm, QWidget* parent)
38 : QGraphicsView(parent)
42 renderGraph(filename, layoutAlgorithm);
46 QY2Graph::QY2Graph(graph_t* graph, QWidget* parent)
47 : QGraphicsView(parent)
63 setRenderHint(QPainter::Antialiasing);
64 setRenderHint(QPainter::TextAntialiasing);
65 setTransformationAnchor(AnchorUnderMouse);
66 setResizeAnchor(AnchorUnderMouse);
68 scene =
new QGraphicsScene(
this);
69 scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
75 QY2Graph::keyPressEvent(QKeyEvent* event)
87 case Qt::Key_Asterisk:
96 QGraphicsView::keyPressEvent(event);
102 QY2Graph::wheelEvent(QWheelEvent* event)
104 scaleView(pow(2.0, -event->delta() / 240.0));
109 QY2Graph::scaleView(qreal scaleFactor)
111 qreal f = sqrt(matrix().det());
113 if (scaleFactor * f > 8.0)
114 scaleFactor = 8.0 / f;
115 if (scaleFactor * f < 0.1)
116 scaleFactor = 0.1 / f;
118 scale(scaleFactor, scaleFactor);
123 QY2Graph::contextMenuEvent(QContextMenuEvent* event)
128 emit nodeContextMenuEvent(event, node->name);
130 emit backgroundContextMenuEvent(event);
135 QY2Graph::mouseDoubleClickEvent(QMouseEvent* event)
140 emit nodeDoubleClickEvent(event, node->name);
145 QY2Graph::gToQ(
const pointf& p,
bool upside_down)
const
147 return upside_down ? QPointF(p.x, graphRect.height() - p.y) : QPointF(p.x, -p.y);
152 QY2Graph::aggetToQString(
void* obj,
const char* name,
const QString& fallback)
const
154 const char* tmp = agget(obj, const_cast<char*>(name));
155 if (tmp == NULL || strlen(tmp) == 0)
157 return QString::fromUtf8(tmp);
162 QY2Graph::aggetToQColor(
void* obj,
const char* name,
const QColor& fallback)
const
164 const char* tmp = agget(obj, const_cast<char*>(name));
165 if (tmp == NULL || strlen(tmp) == 0)
172 QY2Graph::aggetToQPenStyle(
void* obj,
const char* name,
const Qt::PenStyle fallback)
const
174 const char* tmp = agget(obj, const_cast<char*>(name));
175 if (tmp == NULL || strlen(tmp) == 0)
177 if (strcmp(tmp,
"dashed") == 0)
179 if (strcmp(tmp,
"dotted") == 0)
186 QY2Graph::makeBezier(
const bezier& bezier)
const
189 path.moveTo(gToQ(bezier.list[0]));
190 for (
int i = 1; i < bezier.size - 1; i += 3)
191 path.cubicTo(gToQ(bezier.list[i]), gToQ(bezier.list[i+1]), gToQ(bezier.list[i+2]));
197 QY2Graph::drawArrow(
const QLineF& line,
const QColor& color, QPainter* painter)
const
199 QLineF n(line.normalVector());
200 QPointF o(n.dx() / 3.0, n.dy() / 3.0);
203 polygon.append(line.p1() + o);
204 polygon.append(line.p2());
205 polygon.append(line.p1() - o);
209 painter->setPen(pen);
212 painter->setBrush(brush);
214 painter->drawPolygon(polygon);
219 QY2Graph::renderGraph(
const std::string& filename,
const std::string& layoutAlgorithm)
221 FILE* fp = fopen(filename.c_str(),
"r");
224 GVC_t* gvc = gvContext();
227 graph_t* graph = agread(fp);
230 if (gvLayout(gvc, graph, const_cast<char*>(layoutAlgorithm.c_str())) == 0)
234 gvFreeLayout(gvc, graph);
238 qCritical(
"gvLayout() failed");
245 qCritical(
"agread() failed");
252 qCritical(
"gvContext() failed");
259 qCritical(
"failed to open %s", filename.c_str());
265 QY2Graph::makeShapeHelper(node_t* node)
const
267 const polygon_t* poly = (polygon_t*) ND_shape_info(node);
269 if (poly->peripheries != 1)
271 qWarning(
"unsupported number of peripheries %d", poly->peripheries);
274 const int sides = poly->sides;
275 const pointf* vertices = poly->vertices;
278 for (
int side = 0; side < sides; side++)
279 polygon.append(gToQ(vertices[side],
false));
285 QY2Graph::makeShape(node_t* node)
const
289 const char* name = ND_shape(node)->name;
291 if ((strcmp(name,
"rectangle") == 0) ||
292 (strcmp(name,
"box") == 0) ||
293 (strcmp(name,
"hexagon") == 0) ||
294 (strcmp(name,
"polygon") == 0) ||
295 (strcmp(name,
"diamond") == 0))
297 QPolygonF polygon = makeShapeHelper(node);
298 polygon.append(polygon[0]);
299 path.addPolygon(polygon);
301 else if ((strcmp(name,
"ellipse") == 0) ||
302 (strcmp(name,
"circle") == 0))
304 QPolygonF polygon = makeShapeHelper(node);
305 path.addEllipse(QRectF(polygon[0], polygon[1]));
309 qWarning(
"unsupported shape %s", name);
317 QY2Graph::drawLabel(
const textlabel_t* textlabel, QPainter* painter)
const
319 painter->setPen(textlabel->fontcolor);
323 QFont font(textlabel->fontname, textlabel->fontsize);
324 font.setPixelSize(textlabel->fontsize);
326 if (!font.exactMatch())
328 QFontInfo fontinfo(font);
329 qWarning(
"replacing font \"%s\" by font \"%s\"", font.family().toUtf8().data(),
330 fontinfo.family().toUtf8().data());
333 painter->setFont(font);
335 QString text(QString::fromUtf8(textlabel->text));
336 QFontMetricsF fm(painter->fontMetrics());
337 QRectF rect(fm.boundingRect(text));
338 rect.moveCenter(gToQ(textlabel->pos,
false));
339 painter->drawText(rect.adjusted(-2, -2, +2, +2), Qt::AlignCenter, text);
344 QY2Graph::clearGraph()
346 QList<QGraphicsItem*> items(scene->items());
347 while (!items.isEmpty())
348 delete items.takeFirst();
353 QY2Graph::renderGraph(graph_t* graph)
357 if (GD_charset(graph) != 0)
359 qWarning(
"unsupported charset");
363 graphRect = QRectF(GD_bb(graph).LL.x, GD_bb(graph).LL.y, GD_bb(graph).UR.x, GD_bb(graph).UR.y);
364 scene->setSceneRect(graphRect.adjusted(-5, -5, +5, +5));
366 scene->setBackgroundBrush(aggetToQColor(graph,
"bgcolor", Qt::white));
368 for (node_t* node = agfstnode(graph); node != NULL; node = agnxtnode(graph, node))
373 painter.begin(&picture);
374 painter.initFrom(
this);
375 drawLabel(ND_label(node), &painter);
378 QY2Node* item =
new QY2Node(makeShape(node), picture, node->name);
380 item->setPos(gToQ(ND_coord(node)));
382 QPen pen(aggetToQColor(node,
"color", Qt::black));
386 QBrush brush(aggetToQColor(node,
"fillcolor", Qt::gray));
387 item->setBrush(brush);
389 QString tooltip = aggetToQString(node,
"tooltip",
"");
390 if (!tooltip.isEmpty())
392 tooltip.replace(
"\\n",
"\n");
393 item->setToolTip(tooltip);
396 scene->addItem(item);
398 for (edge_t* edge = agfstout(graph, node); edge != NULL; edge = agnxtout(graph, edge))
400 const splines* spl = ED_spl(edge);
404 for (
int i = 0; i < spl->size; ++i)
406 const bezier& bz = spl->list[i];
408 QColor color(aggetToQColor(edge,
"color", Qt::black));
410 QPainterPath path(makeBezier(bz));
415 painter.begin(&picture);
417 drawArrow(QLineF(gToQ(bz.list[0]), gToQ(bz.sp)), color, &painter);
419 drawArrow(QLineF(gToQ(bz.list[bz.size-1]), gToQ(bz.ep)), color, &painter);
425 pen.setStyle(aggetToQPenStyle(edge,
"style", Qt::SolidLine));
429 item->setZValue(-1.0);
431 scene->addItem(item);
438 QY2Node::QY2Node(
const QPainterPath& path,
const QPicture& picture,
const QString& name)
439 : QGraphicsPathItem(path),
447 QY2Node::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option, QWidget* widget)
450 QGraphicsPathItem::paint(painter, option, widget);
453 picture.play(painter);
457 QY2Edge::QY2Edge(
const QPainterPath& path,
const QPicture& picture)
458 : QGraphicsPathItem(path),
465 QY2Edge::boundingRect()
const
467 return QGraphicsPathItem::boundingRect().united(picture.boundingRect());
472 QY2Edge::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option, QWidget* widget)
475 QGraphicsPathItem::paint(painter, option, widget);
478 picture.play(painter);
482 #include "QY2Graph.moc"