25 #include <QWheelEvent> 26 #include <QGraphicsSceneMouseEvent> 31 QY2Graph::QY2Graph(
const std::string& filename,
const std::string& layoutAlgorithm, QWidget* parent)
32 : QGraphicsView(parent)
36 renderGraph(filename, layoutAlgorithm);
40 QY2Graph::QY2Graph(graph_t* graph, QWidget* parent)
41 : QGraphicsView(parent)
57 setRenderHint(QPainter::Antialiasing);
58 setRenderHint(QPainter::TextAntialiasing);
59 setTransformationAnchor(AnchorUnderMouse);
60 setResizeAnchor(AnchorUnderMouse);
62 scene =
new QGraphicsScene(
this);
63 scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex);
69 QY2Graph::keyPressEvent(QKeyEvent* event)
81 case Qt::Key_Asterisk:
90 QGraphicsView::keyPressEvent(event);
96 QY2Graph::wheelEvent(QWheelEvent* event)
98 scaleView(pow(2.0, -event->delta() / 240.0));
103 QY2Graph::scaleView(qreal scaleFactor)
105 qreal f = sqrt(matrix().determinant());
107 if (scaleFactor * f > 8.0)
108 scaleFactor = 8.0 / f;
109 if (scaleFactor * f < 0.1)
110 scaleFactor = 0.1 / f;
112 scale(scaleFactor, scaleFactor);
117 QY2Graph::contextMenuEvent(QContextMenuEvent* event)
122 emit nodeContextMenuEvent(event, node->name);
124 emit backgroundContextMenuEvent(event);
129 QY2Graph::mouseDoubleClickEvent(QMouseEvent* event)
134 emit nodeDoubleClickEvent(event, node->name);
139 QY2Graph::gToQ(
const pointf& p,
bool upside_down)
const 141 return upside_down ? QPointF(p.x, graphRect.height() - p.y) : QPointF(p.x, -p.y);
146 QY2Graph::aggetToQString(
void* obj,
const char* name,
const QString& fallback)
const 148 const char* tmp = agget(obj, const_cast<char*>(name));
149 if (tmp == NULL || strlen(tmp) == 0)
151 return QString::fromUtf8(tmp);
156 QY2Graph::aggetToQColor(
void* obj,
const char* name,
const QColor& fallback)
const 158 const char* tmp = agget(obj, const_cast<char*>(name));
159 if (tmp == NULL || strlen(tmp) == 0)
166 QY2Graph::aggetToQPenStyle(
void* obj,
const char* name,
const Qt::PenStyle fallback)
const 168 const char* tmp = agget(obj, const_cast<char*>(name));
169 if (tmp == NULL || strlen(tmp) == 0)
171 if (strcmp(tmp,
"dashed") == 0)
173 if (strcmp(tmp,
"dotted") == 0)
180 QY2Graph::makeBezier(
const bezier& bezier)
const 183 path.moveTo(gToQ(bezier.list[0]));
184 for (
int i = 1; i < bezier.size - 1; i += 3)
185 path.cubicTo(gToQ(bezier.list[i]), gToQ(bezier.list[i+1]), gToQ(bezier.list[i+2]));
191 QY2Graph::drawArrow(
const QLineF& line,
const QColor& color, QPainter* painter)
const 193 QLineF n(line.normalVector());
194 QPointF o(n.dx() / 3.0, n.dy() / 3.0);
197 polygon.append(line.p1() + o);
198 polygon.append(line.p2());
199 polygon.append(line.p1() - o);
203 painter->setPen(pen);
206 painter->setBrush(brush);
208 painter->drawPolygon(polygon);
213 QY2Graph::renderGraph(
const std::string& filename,
const std::string& layoutAlgorithm)
215 FILE* fp = fopen(filename.c_str(),
"r");
218 GVC_t* gvc = gvContext();
222 graph_t* graph = agread(fp, NULL);
224 graph_t* graph = agread(fp);
228 if (gvLayout(gvc, graph, const_cast<char*>(layoutAlgorithm.c_str())) == 0)
232 gvFreeLayout(gvc, graph);
236 qCritical(
"gvLayout() failed");
243 qCritical(
"agread() failed");
250 qCritical(
"gvContext() failed");
257 qCritical(
"failed to open %s", filename.c_str());
263 QY2Graph::makeShapeHelper(node_t* node)
const 265 const polygon_t* poly = (polygon_t*) ND_shape_info(node);
267 if (poly->peripheries != 1)
269 qWarning(
"unsupported number of peripheries %d", poly->peripheries);
272 const int sides = poly->sides;
273 const pointf* vertices = poly->vertices;
276 for (
int side = 0; side < sides; side++)
277 polygon.append(gToQ(vertices[side],
false));
283 QY2Graph::makeShape(node_t* node)
const 287 const char* name = ND_shape(node)->name;
289 if ((strcmp(name,
"rectangle") == 0) ||
290 (strcmp(name,
"box") == 0) ||
291 (strcmp(name,
"hexagon") == 0) ||
292 (strcmp(name,
"polygon") == 0) ||
293 (strcmp(name,
"diamond") == 0))
295 QPolygonF polygon = makeShapeHelper(node);
296 polygon.append(polygon[0]);
297 path.addPolygon(polygon);
299 else if ((strcmp(name,
"ellipse") == 0) ||
300 (strcmp(name,
"circle") == 0))
302 QPolygonF polygon = makeShapeHelper(node);
303 path.addEllipse(QRectF(polygon[0], polygon[1]));
307 qWarning(
"unsupported shape %s", name);
315 QY2Graph::drawLabel(
const textlabel_t* textlabel, QPainter* painter)
const 317 painter->setPen(textlabel->fontcolor);
321 QFont font(textlabel->fontname, textlabel->fontsize);
322 font.setPixelSize(textlabel->fontsize);
324 if (!font.exactMatch())
326 QFontInfo fontinfo(font);
327 qWarning(
"replacing font \"%s\" by font \"%s\"", font.family().toUtf8().data(),
328 fontinfo.family().toUtf8().data());
331 painter->setFont(font);
333 QString text(QString::fromUtf8(textlabel->text));
334 QFontMetricsF fm(painter->fontMetrics());
335 QRectF rect(fm.boundingRect(text));
336 rect.moveCenter(gToQ(textlabel->pos,
false));
337 painter->drawText(rect.adjusted(-2, -2, +2, +2), Qt::AlignCenter, text);
342 QY2Graph::clearGraph()
344 QList<QGraphicsItem*> items(scene->items());
345 while (!items.isEmpty())
346 delete items.takeFirst();
351 QY2Graph::renderGraph(graph_t* graph)
355 if (GD_charset(graph) != 0)
357 qWarning(
"unsupported charset");
361 graphRect = QRectF(GD_bb(graph).LL.x, GD_bb(graph).LL.y, GD_bb(graph).UR.x, GD_bb(graph).UR.y);
362 scene->setSceneRect(graphRect.adjusted(-5, -5, +5, +5));
364 scene->setBackgroundBrush(aggetToQColor(graph,
"bgcolor", Qt::white));
366 for (node_t* node = agfstnode(graph); node != NULL; node = agnxtnode(graph, node))
371 painter.begin(&picture);
372 painter.initFrom(
this);
373 drawLabel(ND_label(node), &painter);
377 QY2Node* item =
new QY2Node(makeShape(node), picture, agnameof(node));
379 QY2Node* item =
new QY2Node(makeShape(node), picture, node->name);
382 item->setPos(gToQ(ND_coord(node)));
384 QPen pen(aggetToQColor(node,
"color", Qt::black));
388 QBrush brush(aggetToQColor(node,
"fillcolor", Qt::gray));
389 item->setBrush(brush);
391 QString tooltip = aggetToQString(node,
"tooltip",
"");
392 if (!tooltip.isEmpty())
394 tooltip.replace(
"\\n",
"\n");
395 item->setToolTip(tooltip);
398 scene->addItem(item);
400 for (edge_t* edge = agfstout(graph, node); edge != NULL; edge = agnxtout(graph, edge))
402 const splines* spl = ED_spl(edge);
406 for (
int i = 0; i < spl->size; ++i)
408 const bezier& bz = spl->list[i];
410 QColor color(aggetToQColor(edge,
"color", Qt::black));
412 QPainterPath path(makeBezier(bz));
417 painter.begin(&picture);
419 drawArrow(QLineF(gToQ(bz.list[0]), gToQ(bz.sp)), color, &painter);
421 drawArrow(QLineF(gToQ(bz.list[bz.size-1]), gToQ(bz.ep)), color, &painter);
427 pen.setStyle(aggetToQPenStyle(edge,
"style", Qt::SolidLine));
431 item->setZValue(-1.0);
433 scene->addItem(item);
440 QY2Node::QY2Node(
const QPainterPath& path,
const QPicture& picture,
const QString& name)
441 : QGraphicsPathItem(path),
449 QY2Node::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option, QWidget* widget)
452 QGraphicsPathItem::paint(painter, option, widget);
455 picture.play(painter);
459 QY2Edge::QY2Edge(
const QPainterPath& path,
const QPicture& picture)
460 : QGraphicsPathItem(path),
467 QY2Edge::boundingRect()
const 469 return QGraphicsPathItem::boundingRect().united(picture.boundingRect());
474 QY2Edge::paint(QPainter* painter,
const QStyleOptionGraphicsItem* option, QWidget* widget)
477 QGraphicsPathItem::paint(painter, option, widget);
480 picture.play(painter);
484 #include "QY2Graph.moc"