From f5aa6982251a5ff329f05ab298bad65b7b295097 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Mon, 23 Mar 2015 11:44:57 +0100 Subject: [PATCH] ui: separated GraphView style settings into class GraphViewStyle This change adds the class GraphViewStyle that holds all values for defining the style of Nodes and Edges in the Graph. The GraphViewStyleImpl interface and the QtGraphViewStyleImpl implementation are used to request Qt specific metrics, like the charwidth of used fonts. This change includes the following fixes: * aggregation number always in the middle between nodes * darker color for aggregation edge * split off QGraphicsLineItem implementations from QtGraphEdge * fixed some colors in color scheme fortune cookie message = Sorge dich nicht! Du wirst bekommen was du brauchst. --- bin/app/data/ApplicationSettings_template.xml | 32 +- src/app/CMakeLists.txt | 10 +- src/app/qt/graphics/QtAngledLineItem.cpp | 293 ++++++++++ src/app/qt/graphics/QtAngledLineItem.h | 38 ++ ...ndedRectItem.cpp => QtRoundedRectItem.cpp} | 14 +- ...sRoundedRectItem.h => QtRoundedRectItem.h} | 6 +- src/app/qt/graphics/QtStraightLineItem.cpp | 89 +++ src/app/qt/graphics/QtStraightLineItem.h | 26 + src/app/qt/view/QtGraphView.cpp | 22 +- src/app/qt/view/QtGraphView.h | 2 +- src/app/qt/view/QtGraphViewStyleImpl.cpp | 8 + src/app/qt/view/QtGraphViewStyleImpl.h | 14 + src/app/qt/view/QtViewFactory.cpp | 3 + src/app/qt/view/graphElements/QtGraphEdge.cpp | 521 +----------------- src/app/qt/view/graphElements/QtGraphEdge.h | 50 -- src/app/qt/view/graphElements/QtGraphNode.cpp | 265 +++------ src/app/qt/view/graphElements/QtGraphNode.h | 20 +- .../view/graphElements/QtGraphNodeAccess.cpp | 36 +- .../qt/view/graphElements/QtGraphNodeAccess.h | 2 + src/lib/CMakeLists.txt | 5 + .../component/controller/GraphController.cpp | 149 +---- .../component/controller/GraphController.h | 19 - src/lib/component/view/GraphView.cpp | 9 - src/lib/component/view/GraphView.h | 17 +- src/lib/component/view/GraphViewStyle.cpp | 401 ++++++++++++++ src/lib/component/view/GraphViewStyle.h | 103 ++++ src/lib/component/view/GraphViewStyleImpl.h | 12 + .../component/view/graphElements/GraphNode.h | 8 +- src/lib/utility/utility.cpp | 35 ++ src/lib/utility/utility.h | 55 +- 30 files changed, 1255 insertions(+), 1009 deletions(-) create mode 100644 src/app/qt/graphics/QtAngledLineItem.cpp create mode 100644 src/app/qt/graphics/QtAngledLineItem.h rename src/app/qt/graphics/{QtGraphicsRoundedRectItem.cpp => QtRoundedRectItem.cpp} (55%) rename src/app/qt/graphics/{QtGraphicsRoundedRectItem.h => QtRoundedRectItem.h} (78%) create mode 100644 src/app/qt/graphics/QtStraightLineItem.cpp create mode 100644 src/app/qt/graphics/QtStraightLineItem.h create mode 100644 src/app/qt/view/QtGraphViewStyleImpl.cpp create mode 100644 src/app/qt/view/QtGraphViewStyleImpl.h create mode 100644 src/lib/component/view/GraphViewStyle.cpp create mode 100644 src/lib/component/view/GraphViewStyle.h create mode 100644 src/lib/component/view/GraphViewStyleImpl.h create mode 100644 src/lib/utility/utility.cpp diff --git a/bin/app/data/ApplicationSettings_template.xml b/bin/app/data/ApplicationSettings_template.xml index 27c846f7..340f4ac2 100644 --- a/bin/app/data/ApplicationSettings_template.xml +++ b/bin/app/data/ApplicationSettings_template.xml @@ -50,15 +50,15 @@ #ededed - #dddddd + #ededed #ededed - #dddddd + #ededed #ededed - #dddddd + #ededed #ffe47a @@ -77,32 +77,28 @@ #62b29d - #ededed - #dddddd + #00000000 + #00000000 - #ededed - #dddddd + #9ab4ad + #62b29d - #ededed - #dddddd + #ffe47a + #ffcc00 #ededed - #dddddd + #ededed - - #ededed - #dddddd - - #ededed - #dddddd + #00000000 + #00000000 #ededed - #dddddd + #ededed #9ab4ad @@ -110,7 +106,7 @@ #ededed - #dddddd + #ededed #A3BA8A diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 93b88d55..d4a12059 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -26,8 +26,12 @@ add_files( qt/element/QtUndoRedo.cpp qt/element/QtUndoRedo.h - qt/graphics/QtGraphicsRoundedRectItem.cpp - qt/graphics/QtGraphicsRoundedRectItem.h + qt/graphics/QtAngledLineItem.cpp + qt/graphics/QtAngledLineItem.h + qt/graphics/QtRoundedRectItem.cpp + qt/graphics/QtRoundedRectItem.h + qt/graphics/QtStraightLineItem.cpp + qt/graphics/QtStraightLineItem.h qt/utility/QtDeviceScaledPixmap.h qt/utility/QtGraphPostprocessor.cpp @@ -58,6 +62,8 @@ add_files( qt/view/QtCompositeView.h qt/view/QtGraphView.cpp qt/view/QtGraphView.h + qt/view/QtGraphViewStyleImpl.cpp + qt/view/QtGraphViewStyleImpl.h qt/view/QtMainView.cpp qt/view/QtMainView.h qt/view/QtRefreshView.cpp diff --git a/src/app/qt/graphics/QtAngledLineItem.cpp b/src/app/qt/graphics/QtAngledLineItem.cpp new file mode 100644 index 00000000..aeddfd1e --- /dev/null +++ b/src/app/qt/graphics/QtAngledLineItem.cpp @@ -0,0 +1,293 @@ +#include "qt/graphics/QtAngledLineItem.h" + +#include + +#include + +#include "utility/math/Vector2.h" + +QtAngledLineItem::QtAngledLineItem(QGraphicsItem* parent) + : QGraphicsLineItem(parent) +{ + this->setAcceptHoverEvents(true); +} + +QtAngledLineItem::~QtAngledLineItem() +{ +} + +void QtAngledLineItem::updateLine( + Vec4i ownerRect, Vec4i targetRect, + Vec4i ownerParentRect, Vec4i targetParentRect, + GraphViewStyle::EdgeStyle style +){ + prepareGeometryChange(); + + m_ownerRect = ownerRect; + m_targetRect = targetRect; + m_ownerParentRect = ownerParentRect; + m_targetParentRect = targetParentRect; + + m_ownerRect.x = m_ownerRect.x - 1; + m_ownerRect.z = m_ownerRect.z + 1; + m_targetRect.x = m_targetRect.x - 1; + m_targetRect.z = m_targetRect.z + 1; + + m_style = style; + + this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap)); +} + +QPainterPath QtAngledLineItem::shape() const +{ + int w = m_style.arrowWidth / 2 + 1; + QPainterPath path; + QPolygon poly = getPath(); + for (int i = 0; i < poly.size() - 1; i++) + { + path.addRect(QRectF(poly.at(i), poly.at(i + 1)).normalized().adjusted(-w, -w, w, w)); + } + return path; +} + +void QtAngledLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget) +{ + painter->setPen(pen()); + + QPainterPath path; + + QPolygon poly = getPath(); + int i = poly.length() - 1; + + path.moveTo(poly.at(i)); + + int radius = m_style.cornerRadius; + int dir = getDirection(poly.at(i), poly.at(i - 1)); + while (i > 1) + { + i--; + + QPointF a = poly.at(i); + QPointF b = poly.at(i - 1); + + int newDir = getDirection(a, b); + int ar = radius; + int br = m_style.cornerRadius; + + if (i != 1) + { + if (dir % 2 == 1 && std::abs(a.y() - b.y()) < 2 * br) + { + br = std::abs(a.y() - b.y()) / 2; + } + else if (dir % 2 == 0 && std::abs(a.x() - b.x()) < 2 * br) + { + br = std::abs(a.x() - b.x()) / 2; + } + } + + switch (dir) + { + case 0: a.setY(a.y() + ar); break; + case 1: a.setX(a.x() - ar); break; + case 2: a.setY(a.y() - ar); break; + case 3: a.setX(a.x() + ar); break; + } + + b = poly.at(i); + switch (newDir) + { + case 0: b.setY(b.y() - br); break; + case 1: b.setX(b.x() + br); break; + case 2: b.setY(b.y() + br); break; + case 3: b.setX(b.x() - br); break; + } + + switch (dir) + { + case 0: + if (newDir == 1) + { + path.arcTo(a.x(), b.y(), 2 * br, 2 * ar, 180, -90); + } + else if (newDir == 3) + { + path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, 90); + } + break; + case 1: + if (newDir == 0) + { + path.arcTo(a.x() - ar, b.y() - br, 2 * ar, 2 * br, -90, 90); + } + else if (newDir == 2) + { + path.arcTo(a.x() - ar, a.y(), 2 * ar, 2 * br, 90, -90); + } + break; + case 2: + if (newDir == 1) + { + path.arcTo(a.x(), a.y() - ar, 2 * br, 2 * ar, 180, 90); + } + else if (newDir == 3) + { + path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, -90); + } + break; + case 3: + if (newDir == 0) + { + path.arcTo(b.x(), b.y() - br, 2 * ar, 2 * br, -90, -90); + } + else if (newDir == 2) + { + path.arcTo(b.x(), a.y(), 2 * ar, 2 * br, 90, 90); + } + break; + } + + dir = newDir; + radius = br; + } + + QPointF arrow = poly.at(0) + QPointF((poly.at(0).x() - poly.at(1).x() > 0 ? -1 : 1) * m_style.arrowLength, 0); + + if (m_style.arrowClosed) + { + path.lineTo(arrow); + path.moveTo(poly.at(0)); + } + else + { + path.lineTo(poly.at(0)); + } + + arrow.setY(arrow.y() - m_style.arrowWidth / 2); + path.lineTo(arrow); + arrow.setY(arrow.y() + m_style.arrowWidth); + + if (m_style.arrowClosed) + { + path.lineTo(arrow); + } + else + { + path.moveTo(arrow); + } + path.lineTo(poly.at(0)); + + painter->drawPath(path); +} + +QPolygon QtAngledLineItem::getPath() const +{ + const Vec4i& oR = m_ownerRect; + const Vec4i& tR = m_targetRect; + + Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (oR.y + 2 * oR.w) / 3), Vec2f(m_ownerParentRect.z, (oR.y + 2 * oR.w) / 3) }; + Vec2f t[2] = { Vec2f(m_targetParentRect.x, (2 * tR.y + tR.w) / 3), Vec2f(m_targetParentRect.z, (2 * tR.y + tR.w) / 3) }; + + int io = -1; + int it = -1; + float dist = -1; + + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + Vec2f diff = o[i] - t[j]; + if (dist < 0 || diff.getLength() < dist) + { + dist = diff.getLength(); + io = i; + it = j; + } + } + } + + QPoint tp((it ? 1 : -1) * m_style.targetOffset.x + t[it].x, t[it].y + m_style.targetOffset.y); + QPoint op((io ? 1 : -1) * m_style.originOffset.x + o[io].x, o[io].y + m_style.originOffset.y); + + if (it != io) + { + if (it && tp.x() < op.x()) + { + io = 0; + op = QPoint(o[io].x - m_style.originOffset.x, o[io].y + m_style.originOffset.y); + } + else if (!it && tp.x() < op.x()) + { + it = 1; + tp = QPoint(t[it].x + m_style.targetOffset.x, t[it].y + m_style.targetOffset.y); + } + else if (io && tp.x() > op.x()) + { + io = 1; + op = QPoint(o[io].x + m_style.originOffset.x, o[io].y + m_style.originOffset.y); + } + else if (!io && tp.x() > op.x()) + { + it = 0; + tp = QPoint(t[it].x - m_style.targetOffset.x, t[it].y + m_style.targetOffset.y); + } + } + + if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())) ) + { + tp.setX(op.x()); + } + else + { + op.setX(tp.x()); + } + + o[0] = Vec2f(oR.x, (oR.y + 2 * oR.w) / 3); + o[1] = Vec2f(oR.z, (oR.y + 2 * oR.w) / 3); + t[0] = Vec2f(tR.x, (2 * tR.y + tR.w) / 3); + t[1] = Vec2f(tR.z, (2 * tR.y + tR.w) / 3); + + if (o[io].y < t[it].y) + { + op.setX(op.x() + m_style.verticalOffset); + tp.setX(tp.x() + m_style.verticalOffset); + } + else + { + op.setX(op.x() - m_style.verticalOffset); + tp.setX(tp.x() - m_style.verticalOffset); + } + + QPolygon poly; + poly << QPoint(t[it].x, t[it].y + m_style.targetOffset.y); + poly << tp; + poly << op; + poly << QPoint(o[io].x, o[io].y + m_style.originOffset.y); + return poly; +} + +int QtAngledLineItem::getDirection(const QPointF& a, const QPointF& b) const +{ + if (a.x() != b.x()) + { + if (a.x() < b.x()) + { + return 1; + } + else + { + return 3; + } + } + else + { + if (a.y() < b.y()) + { + return 2; + } + else + { + return 0; + } + } +} diff --git a/src/app/qt/graphics/QtAngledLineItem.h b/src/app/qt/graphics/QtAngledLineItem.h new file mode 100644 index 00000000..46ab6ddd --- /dev/null +++ b/src/app/qt/graphics/QtAngledLineItem.h @@ -0,0 +1,38 @@ +#ifndef QT_ANGLED_LINE_ITEM_H +#define QT_ANGLED_LINE_ITEM_H + +#include + +#include "utility/math/Vector4.h" + +#include "component/view/GraphViewStyle.h" + +class QtAngledLineItem + : public QGraphicsLineItem +{ +public: + QtAngledLineItem(QGraphicsItem* parent); + virtual ~QtAngledLineItem(); + + void updateLine( + Vec4i ownerRect, Vec4i targetRect, + Vec4i ownerParentRect, Vec4i targetParentRect, + GraphViewStyle::EdgeStyle style); + + virtual QPainterPath shape() const; + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget); + +private: + QPolygon getPath() const; + int getDirection(const QPointF& a, const QPointF& b) const; + + Vec4i m_ownerRect; + Vec4i m_targetRect; + + Vec4i m_ownerParentRect; + Vec4i m_targetParentRect; + + GraphViewStyle::EdgeStyle m_style; +}; + +#endif // QT_ANGLED_LINE_ITEM_H diff --git a/src/app/qt/graphics/QtGraphicsRoundedRectItem.cpp b/src/app/qt/graphics/QtRoundedRectItem.cpp similarity index 55% rename from src/app/qt/graphics/QtGraphicsRoundedRectItem.cpp rename to src/app/qt/graphics/QtRoundedRectItem.cpp index 40abbbe4..b5001642 100644 --- a/src/app/qt/graphics/QtGraphicsRoundedRectItem.cpp +++ b/src/app/qt/graphics/QtRoundedRectItem.cpp @@ -1,20 +1,20 @@ -#include "qt/graphics/QtGraphicsRoundedRectItem.h" +#include "qt/graphics/QtRoundedRectItem.h" #include #include -QtGraphicsRoundedRectItem::QtGraphicsRoundedRectItem(QGraphicsItem* parent) +QtRoundedRectItem::QtRoundedRectItem(QGraphicsItem* parent) : QGraphicsRectItem(parent) , m_radius(0.0f) { this->setZValue(-1.0f); } -QtGraphicsRoundedRectItem::~QtGraphicsRoundedRectItem() +QtRoundedRectItem::~QtRoundedRectItem() { } -void QtGraphicsRoundedRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget) +void QtRoundedRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget) { painter->setPen(pen()); painter->setBrush(brush()); @@ -24,7 +24,7 @@ void QtGraphicsRoundedRectItem::paint(QPainter *painter, const QStyleOptionGraph painter->drawRoundedRect(this->rect(), m_radius, m_radius); } -void QtGraphicsRoundedRectItem::setShadow(QColor color, int blurRadius) +void QtRoundedRectItem::setShadow(QColor color, int blurRadius) { QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect(); effect->setColor(color); @@ -33,7 +33,7 @@ void QtGraphicsRoundedRectItem::setShadow(QColor color, int blurRadius) this->setGraphicsEffect(effect); } -void QtGraphicsRoundedRectItem::setShadowEnabled(bool enabled) +void QtRoundedRectItem::setShadowEnabled(bool enabled) { if (this->graphicsEffect()) { @@ -41,7 +41,7 @@ void QtGraphicsRoundedRectItem::setShadowEnabled(bool enabled) } } -void QtGraphicsRoundedRectItem::setRadius(qreal radius) +void QtRoundedRectItem::setRadius(qreal radius) { m_radius = radius; } diff --git a/src/app/qt/graphics/QtGraphicsRoundedRectItem.h b/src/app/qt/graphics/QtRoundedRectItem.h similarity index 78% rename from src/app/qt/graphics/QtGraphicsRoundedRectItem.h rename to src/app/qt/graphics/QtRoundedRectItem.h index 2526c20f..93dd4ed9 100644 --- a/src/app/qt/graphics/QtGraphicsRoundedRectItem.h +++ b/src/app/qt/graphics/QtRoundedRectItem.h @@ -3,12 +3,12 @@ #include -class QtGraphicsRoundedRectItem +class QtRoundedRectItem : public QGraphicsRectItem { public: - QtGraphicsRoundedRectItem(QGraphicsItem* parent); - virtual ~QtGraphicsRoundedRectItem(); + QtRoundedRectItem(QGraphicsItem* parent); + virtual ~QtRoundedRectItem(); virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget); diff --git a/src/app/qt/graphics/QtStraightLineItem.cpp b/src/app/qt/graphics/QtStraightLineItem.cpp new file mode 100644 index 00000000..d6acf9a4 --- /dev/null +++ b/src/app/qt/graphics/QtStraightLineItem.cpp @@ -0,0 +1,89 @@ +#include "qt/graphics/QtStraightLineItem.h" + +#include +#include +#include + +#include "utility/math/Vector2.h" +#include "utility/utility.h" + +#include "qt/graphics/QtRoundedRectItem.h" + +QtStraightLineItem::QtStraightLineItem(QGraphicsItem* parent) + : QGraphicsLineItem(parent) +{ + this->setAcceptHoverEvents(true); + + m_circle = new QtRoundedRectItem(this); + m_circle->setRadius(10); + m_circle->setBrush(QBrush(QColor("#FFF"))); + m_circle->setAcceptHoverEvents(true); + + QFont font; + font.setFamily(GraphViewStyle::getFontNameOfNumber().c_str()); + font.setPixelSize(GraphViewStyle::getFontSizeOfNumber()); + font.setWeight(QFont::Normal); + + m_number = new QGraphicsSimpleTextItem(this); + m_number->setFont(font); +} + +QtStraightLineItem::~QtStraightLineItem() +{ +} + +void QtStraightLineItem::updateLine(Vec4i ownerRect, Vec4i targetRect, int number, GraphViewStyle::EdgeStyle style) +{ + prepareGeometryChange(); + + const Vec4i& o = ownerRect; + const Vec4i& t = targetRect; + + Vec2f oc((o.x + o.z) / 2, (o.y + o.w) / 2); + Vec2f tc((t.x + t.z) / 2, (t.y + t.w) / 2); + + Vec2f mid; + Vec2f op; + Vec2f tp; + + bool intersects = false; + for (int i = 0; !intersects && i < 4; i++) + { + switch (i) + { + case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.x, o.w), &op); break; + case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.z, o.y), &op); break; + case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.z, o.y), Vec2f(o.z, o.w), &op); break; + case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.w), Vec2f(o.z, o.w), &op); break; + } + } + + intersects = false; + for (int i = 0; !intersects && i < 4; i++) + { + switch (i) + { + case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.x, t.w), &tp); break; + case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.z, t.y), &tp); break; + case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.z, t.y), Vec2f(t.z, t.w), &tp); break; + case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.w), Vec2f(t.z, t.w), &tp); break; + } + } + + mid = (op + tp) / 2; + + this->setLine(oc.x, oc.y, tc.x, tc.y); + + m_circle->setRect(mid.x - 10, mid.y - 10, 20, 20); + m_circle->setPen(QPen(QColor(style.color.c_str()), 2)); + + QString numberStr = QString::number(number); + m_number->setText(numberStr); + m_number->setBrush(QBrush(QColor("#666"))); + m_number->setPos( + mid.x - QFontMetrics(m_number->font()).width(numberStr) / 2, + mid.y - QFontMetrics(m_number->font()).height() / 2 + ); + + this->setPen(QPen(QBrush(style.color.c_str()), number + style.width, Qt::SolidLine, Qt::RoundCap)); +} diff --git a/src/app/qt/graphics/QtStraightLineItem.h b/src/app/qt/graphics/QtStraightLineItem.h new file mode 100644 index 00000000..6f79934e --- /dev/null +++ b/src/app/qt/graphics/QtStraightLineItem.h @@ -0,0 +1,26 @@ +#ifndef QT_STRAIGHT_LINE_ITEM_H +#define QT_STRAIGHT_LINE_ITEM_H + +#include + +#include "utility/math/Vector4.h" + +#include "component/view/GraphViewStyle.h" + +class QtRoundedRectItem; + +class QtStraightLineItem + : public QGraphicsLineItem +{ +public: + QtStraightLineItem(QGraphicsItem* parent); + virtual ~QtStraightLineItem(); + + void updateLine(Vec4i ownerRect, Vec4i targetRect, int number, GraphViewStyle::EdgeStyle style); + +private: + QtRoundedRectItem* m_circle; + QGraphicsSimpleTextItem* m_number; +}; + +#endif // QT_STRAIGHT_LINE_ITEM_H diff --git a/src/app/qt/view/QtGraphView.cpp b/src/app/qt/view/QtGraphView.cpp index a1acdde8..0c08520e 100644 --- a/src/app/qt/view/QtGraphView.cpp +++ b/src/app/qt/view/QtGraphView.cpp @@ -69,19 +69,10 @@ void QtGraphView::clear() m_clearFunctor(); } -GraphView::Metrics QtGraphView::getViewMetrics() const +Vec2i QtGraphView::getViewSize() const { - GraphView::Metrics metrics; QGraphicsView* view = getView(); - - metrics.width = view->width(); - metrics.height = view->height(); - - metrics.typeNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_CLASS)).width("QtGraphNode") / 11.0f; - metrics.variableNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_FIELD)).width("QtGraphNode") / 11.0f; - metrics.functionNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_METHOD)).width("QtGraphNode") / 11.0f; - - return metrics; + return Vec2i(view->width(), view->height()); } void QtGraphView::finishedTransition() @@ -261,7 +252,7 @@ std::shared_ptr QtGraphView::createNodeRecursive( } } - newNode->setStyle(); + newNode->updateStyle(); return newNode; } @@ -281,11 +272,8 @@ std::shared_ptr QtGraphView::createEdge(QGraphicsView* view, const std::shared_ptr qtEdge = std::make_shared(owner, target, edge.data); qtEdge->setIsActive(edge.active); - bool added = owner->addOutEdge(qtEdge) | target->addInEdge(qtEdge); - if (!added) - { - return NULL; - } + owner->addOutEdge(qtEdge); + target->addInEdge(qtEdge); view->scene()->addItem(qtEdge.get()); diff --git a/src/app/qt/view/QtGraphView.h b/src/app/qt/view/QtGraphView.h index ec4069eb..f884119a 100644 --- a/src/app/qt/view/QtGraphView.h +++ b/src/app/qt/view/QtGraphView.h @@ -35,7 +35,7 @@ public: virtual void rebuildGraph(std::shared_ptr graph, const std::vector& nodes, const std::vector& edges); virtual void clear(); - virtual GraphView::Metrics getViewMetrics() const; + virtual Vec2i getViewSize() const; private slots: void finishedTransition(); diff --git a/src/app/qt/view/QtGraphViewStyleImpl.cpp b/src/app/qt/view/QtGraphViewStyleImpl.cpp new file mode 100644 index 00000000..3bd032bf --- /dev/null +++ b/src/app/qt/view/QtGraphViewStyleImpl.cpp @@ -0,0 +1,8 @@ +#include "qt/view/QtGraphViewStyleImpl.h" + +#include + +float QtGraphViewStyleImpl::getCharWidthForNodeType(Node::NodeType type) +{ + return QFontMetrics(QtGraphNode::getFontForNodeType(type)).width("QtGraphNode::QtGraphNode::QtGraphNode") / 37.0f; +} diff --git a/src/app/qt/view/QtGraphViewStyleImpl.h b/src/app/qt/view/QtGraphViewStyleImpl.h new file mode 100644 index 00000000..9957a9da --- /dev/null +++ b/src/app/qt/view/QtGraphViewStyleImpl.h @@ -0,0 +1,14 @@ +#ifndef QT_GRAPH_VIEW_STYLE_IMPL_H +#define QT_GRAPH_VIEW_STYLE_IMPL_H + +#include "component/view/GraphViewStyleImpl.h" +#include "qt/view/graphElements/QtGraphNode.h" + +class QtGraphViewStyleImpl + : public GraphViewStyleImpl +{ +public: + virtual float getCharWidthForNodeType(Node::NodeType type); +}; + +#endif // QT_GRAPH_VIEW_STYLE_IMPL_H diff --git a/src/app/qt/view/QtViewFactory.cpp b/src/app/qt/view/QtViewFactory.cpp index 81cb8735..1685fc69 100644 --- a/src/app/qt/view/QtViewFactory.cpp +++ b/src/app/qt/view/QtViewFactory.cpp @@ -1,8 +1,10 @@ #include "qt/view/QtViewFactory.h" +#include "component/view/GraphViewStyle.h" #include "qt/view/QtCodeView.h" #include "qt/view/QtCompositeView.h" #include "qt/view/QtGraphView.h" +#include "qt/view/QtGraphViewStyleImpl.h" #include "qt/view/QtMainView.h" #include "qt/view/QtRefreshView.h" #include "qt/view/QtSearchView.h" @@ -38,6 +40,7 @@ std::shared_ptr QtViewFactory::createCodeView(ViewLayout* viewLayout) std::shared_ptr QtViewFactory::createGraphView(ViewLayout* viewLayout) const { + GraphViewStyle::setImpl(std::make_shared()); return View::createInitAndAddToLayout(viewLayout); } diff --git a/src/app/qt/view/graphElements/QtGraphEdge.cpp b/src/app/qt/view/graphElements/QtGraphEdge.cpp index 0dc22b3c..c800e55d 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.cpp +++ b/src/app/qt/view/graphElements/QtGraphEdge.cpp @@ -1,384 +1,16 @@ #include "qt/view/graphElements/QtGraphEdge.h" -#include - #include #include -#include #include #include "utility/messaging/type/MessageActivateTokens.h" #include "component/view/graphElements/GraphNode.h" +#include "component/view/GraphViewStyle.h" #include "data/graph/token_component/TokenComponentAggregation.h" -#include "qt/graphics/QtGraphicsRoundedRectItem.h" - -QtStraightConnection::QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent) - : QGraphicsLineItem(parent) -{ - const Vec4i& o = ownerRect; - const Vec4i& t = targetRect; - - Vec2f a((o.x + o.z) / 2, (o.y + o.w) / 2); - Vec2f b((t.x + t.z) / 2, (t.y + t.w) / 2); - - this->setLine(a.x, a.y, b.x, b.y); - this->setAcceptHoverEvents(true); - - Vec2f mid = (a + b) / 2; - Vec2f u = b - a; - float len = u.getLength(); - u.normalize(); - - float alpha = atan2(u.y, u.x); - - Vec2f w; - w.x = (o.z - o.x) / 2 * cos(alpha); - w.y = (o.w - o.y) / 2 * sin(alpha); - a += u * w.getLength(); - float newLen = w.getLength(); - - w.x = (t.z - t.x) / 2 * cos(alpha); - w.y = (t.w - t.y) / 2 * sin(alpha); - b += u * -w.getLength(); - newLen -= w.getLength(); - - if (newLen > 0 && newLen < len) - { - mid = (a + b) / 2; - } - - m_circle = new QtGraphicsRoundedRectItem(this); - m_circle->setRect(mid.x - 10, mid.y - 10, 20, 20); - m_circle->setRadius(10); - m_circle->setPen(QPen(QColor("#F8F8F8"), 2)); - m_circle->setBrush(QBrush(QColor("#FFF"))); - m_circle->setAcceptHoverEvents(true); - - QFont font; - font.setFamily("Myriad Pro"); - font.setWeight(QFont::Normal); - font.setPixelSize(9); - - m_number = new QGraphicsSimpleTextItem(this); - m_number->setFont(font); - - QString numberStr = QString::number(number); - m_number->setText(numberStr); - m_number->setBrush(QBrush(QColor("#666"))); - m_number->setPos( - mid.x - QFontMetrics(m_number->font()).width(numberStr) / 2, - mid.y - QFontMetrics(m_number->font()).height() / 2 - ); -} - -QtStraightConnection::~QtStraightConnection() -{ -} - -void QtStraightConnection::setColor(QColor color) -{ - QPen p = this->pen(); - p.setColor(color); - this->setPen(p); - - p = m_circle->pen(); - p.setColor(color); - m_circle->setPen(p); -} - -QtCorneredConnection::QtCorneredConnection( - Vec4i ownerRect, Vec4i targetRect, Vec4i ownerParentRect, Vec4i targetParentRect, QGraphicsItem* parent -) - : QGraphicsLineItem(parent) - , m_ownerRect(ownerRect) - , m_targetRect(targetRect) - , m_ownerParentRect(ownerParentRect) - , m_targetParentRect(targetParentRect) - , m_closed(false) - , m_big(false) -{ - this->setAcceptHoverEvents(true); - - m_ownerRect.x = m_ownerRect.x - 1; - m_ownerRect.z = m_ownerRect.z + 1; - m_targetRect.x = m_targetRect.x - 1; - m_targetRect.z = m_targetRect.z + 1; -} - -QtCorneredConnection::~QtCorneredConnection() -{ -} - -QPainterPath QtCorneredConnection::shape() const -{ - int w = m_big ? 10 : 5; - QPainterPath path; - QPolygon poly = getPath(); - for (int i = 0; i < poly.size() - 1; i++) - { - path.addRect(QRectF(poly.at(i), poly.at(i + 1)).normalized().adjusted(-w, -w, w, w)); - } - return path; -} - -void QtCorneredConnection::paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget) -{ - painter->setPen(pen()); - - QPainterPath path; - - QPolygon poly = getPath(); - int i = poly.length() - 1; - - path.moveTo(poly.at(i)); - - int radius = 10; - int dir = getDirection(poly.at(i), poly.at(i - 1)); - while (i > 1) - { - i--; - - QPointF a = poly.at(i); - QPointF b = poly.at(i - 1); - - int newDir = getDirection(a, b); - int ar = radius; - int br = 10; - - if (i != 1) - { - if (dir % 2 == 1 && std::abs(a.y() - b.y()) < 2 * br) - { - br = std::abs(a.y() - b.y()) / 2; - } - else if (dir % 2 == 0 && std::abs(a.x() - b.x()) < 2 * br) - { - br = std::abs(a.x() - b.x()) / 2; - } - } - - switch (dir) - { - case 0: a.setY(a.y() + ar); break; - case 1: a.setX(a.x() - ar); break; - case 2: a.setY(a.y() - ar); break; - case 3: a.setX(a.x() + ar); break; - } - - b = poly.at(i); - switch (newDir) - { - case 0: b.setY(b.y() - br); break; - case 1: b.setX(b.x() + br); break; - case 2: b.setY(b.y() + br); break; - case 3: b.setX(b.x() - br); break; - } - - switch (dir) - { - case 0: - if (newDir == 1) - { - path.arcTo(a.x(), b.y(), 2 * br, 2 * ar, 180, -90); - } - else if (newDir == 3) - { - path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, 90); - } - break; - case 1: - if (newDir == 0) - { - path.arcTo(a.x() - ar, b.y() - br, 2 * ar, 2 * br, -90, 90); - } - else if (newDir == 2) - { - path.arcTo(a.x() - ar, a.y(), 2 * ar, 2 * br, 90, -90); - } - break; - case 2: - if (newDir == 1) - { - path.arcTo(a.x(), a.y() - ar, 2 * br, 2 * ar, 180, 90); - } - else if (newDir == 3) - { - path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, -90); - } - break; - case 3: - if (newDir == 0) - { - path.arcTo(b.x(), b.y() - br, 2 * ar, 2 * br, -90, -90); - } - else if (newDir == 2) - { - path.arcTo(b.x(), a.y(), 2 * ar, 2 * br, 90, 90); - } - break; - } - - dir = newDir; - radius = br; - } - - int arrowLength = m_big ? 15 : 5; - int arrowWidth = m_big ? 20 : 8; - QPointF arrow = poly.at(0) + QPointF((poly.at(0).x() - poly.at(1).x() > 0 ? -1 : 1) * arrowLength, 0); - - if (m_closed) - { - path.lineTo(arrow); - path.moveTo(poly.at(0)); - } - else - { - path.lineTo(poly.at(0)); - } - - arrow.setY(arrow.y() - arrowWidth / 2); - path.lineTo(arrow); - arrow.setY(arrow.y() + arrowWidth); - if (m_closed) - { - path.lineTo(arrow); - } - else - { - path.moveTo(arrow); - } - path.lineTo(poly.at(0)); - - painter->drawPath(path); -} - -void QtCorneredConnection::setClosed(bool closed) -{ - m_closed = closed; -} - -void QtCorneredConnection::setBig(bool big) -{ - m_big = big; -} - -QPolygon QtCorneredConnection::getPath() const -{ - const Vec4i& oR = m_ownerRect; - const Vec4i& tR = m_targetRect; - - Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (oR.y + 2 * oR.w) / 3), Vec2f(m_ownerParentRect.z, (oR.y + 2 * oR.w) / 3) }; - Vec2f t[2] = { Vec2f(m_targetParentRect.x, (2 * tR.y + tR.w) / 3), Vec2f(m_targetParentRect.z, (2 * tR.y + tR.w) / 3) }; - - int io = -1; - int it = -1; - float dist = -1; - - for (int i = 0; i < 2; i++) - { - for (int j = 0; j < 2; j++) - { - Vec2f diff = o[i] - t[j]; - if (dist < 0 || diff.getLength() < dist) - { - dist = diff.getLength(); - io = i; - it = j; - } - } - } - - float offsetO = 17; - float offsetT = m_big ? 29 : 17; - - QPoint tp((it ? 1 : -1) * offsetT + t[it].x, t[it].y); - QPoint op((io ? 1 : -1) * offsetO + o[io].x, o[io].y); - - if (it != io) - { - if (it && tp.x() < op.x()) - { - io = 0; - op = QPoint(o[io].x - offsetO, o[io].y); - } - else if (!it && tp.x() < op.x()) - { - it = 1; - tp = QPoint(t[it].x + offsetT, t[it].y); - } - else if (io && tp.x() > op.x()) - { - io = 1; - op = QPoint(o[io].x + offsetO, o[io].y); - } - else if (!io && tp.x() > op.x()) - { - it = 0; - tp = QPoint(t[it].x - offsetT, t[it].y); - } - } - - if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())) ) - { - tp.setX(op.x()); - } - else - { - op.setX(tp.x()); - } - - o[0] = Vec2f(oR.x, (oR.y + 2 * oR.w) / 3); - o[1] = Vec2f(oR.z, (oR.y + 2 * oR.w) / 3); - t[0] = Vec2f(tR.x, (2 * tR.y + tR.w) / 3); - t[1] = Vec2f(tR.z, (2 * tR.y + tR.w) / 3); - - int verticalOffset = 3; - if (o[io].y < t[it].y) - { - op.setX(op.x() + verticalOffset); - tp.setX(tp.x() + verticalOffset); - } - else - { - op.setX(op.x() - verticalOffset); - tp.setX(tp.x() - verticalOffset); - } - - QPolygon poly; - poly << QPoint(t[it].x, t[it].y); - poly << tp; - poly << op; - poly << QPoint(o[io].x, o[io].y); - return poly; -} - -int QtCorneredConnection::getDirection(const QPointF& a, const QPointF& b) const -{ - if (a.x() != b.x()) - { - if (a.x() < b.x()) - { - return 1; - } - else - { - return 3; - } - } - else - { - if (a.y() < b.y()) - { - return 2; - } - else - { - return 0; - } - } -} - +#include "qt/graphics/QtAngledLineItem.h" +#include "qt/graphics/QtStraightLineItem.h" QtGraphEdge::QtGraphEdge(const std::weak_ptr& owner, const std::weak_ptr& target, const Edge* data) : GraphEdge(data) @@ -389,9 +21,6 @@ QtGraphEdge::QtGraphEdge(const std::weak_ptr& owner, const std::weak_ , m_mousePos(0.0f, 0.0f) , m_mouseMoved(false) { - this->setAcceptHoverEvents(true); - this->setZValue(getZValue(false)); // Used to draw edges always on top of nodes. - this->updateLine(); } @@ -420,61 +49,38 @@ void QtGraphEdge::updateLine() return; } - if (m_child) - { - delete m_child; - } + GraphViewStyle::EdgeStyle style = GraphViewStyle::getStyleForEdgeType(getData()->getType(), m_isActive, false); - if (isAggregation()) + if (style.isStraight) { - m_child = - new QtStraightConnection(owner->getBoundingRect(), target->getBoundingRect(), getAggregationCount(), this); + if (!m_child) + { + m_child = new QtStraightLineItem(this); + } + + int number = 0; + if (getData()->isType(Edge::EDGE_AGGREGATION)) + { + number = getData()->getComponent()->getAggregationCount(); + } + + dynamic_cast(m_child)->updateLine( + owner->getBoundingRect(), target->getBoundingRect(), number, style); } else { - QtCorneredConnection* child = new QtCorneredConnection( - owner->getBoundingRect(), target->getBoundingRect(), - owner->getParentBoundingRect(), target->getParentBoundingRect(), - this - ); - - if (isInheritance()) + if (!m_child) { - child->setClosed(true); - child->setBig(true); + m_child = new QtAngledLineItem(this); } - m_child = child; + dynamic_cast(m_child)->updateLine( + owner->getBoundingRect(), target->getBoundingRect(), + owner->getParentBoundingRect(), target->getParentBoundingRect(), + style); } - QColor color; - - switch (getData()->getType()) - { - case Edge::EDGE_CALL: - color = QColor("#F1C100"); - break; - case Edge::EDGE_USAGE: - color = QColor("#62B29D"); - break; - case Edge::EDGE_INHERITANCE: - case Edge::EDGE_OVERRIDE: - color = QColor("#CC5E89"); - break; - case Edge::EDGE_AGGREGATION: - color = QColor("#F8F8F8"); - break; - case Edge::EDGE_INCLUDE: - color = QColor("#87BA50"); - break; - default: - color = QColor("#878787"); - break; - } - - m_child->setPen(QPen(color, getPenWidth(), Qt::SolidLine, Qt::RoundCap)); - - setIsActive(m_isActive); + this->setZValue(style.zValue); // Used to draw edges always on top of nodes. } bool QtGraphEdge::getIsActive() const @@ -486,39 +92,12 @@ void QtGraphEdge::setIsActive(bool isActive) { m_isActive = isActive; - if (isActive) - { - if (isAggregation()) - { - dynamic_cast(m_child)->setColor(QColor("#EEE")); - } - else - { - QPen p = m_child->pen(); - p.setWidthF(getPenWidth() + 1); - m_child->setPen(p); - } - this->setZValue(getZValue(isActive)); - } - else - { - if (isAggregation()) - { - dynamic_cast(m_child)->setColor(QColor("#F8F8F8")); - } - else - { - QPen p = m_child->pen(); - p.setWidthF(getPenWidth()); - m_child->setPen(p); - } - this->setZValue(getZValue(isActive)); - } + updateLine(); } void QtGraphEdge::onClick() { - if (isAggregation()) + if (getData()->isType(Edge::EDGE_AGGREGATION)) { const std::set& ids = getData()->getComponent()->getAggregationIds(); MessageActivateTokens message(std::vector(ids.begin(), ids.end())); @@ -568,49 +147,3 @@ void QtGraphEdge::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { this->setIsActive(m_isActive); } - -bool QtGraphEdge::isAggregation() const -{ - return getData()->getType() == Edge::EDGE_AGGREGATION; -} - -bool QtGraphEdge::isInheritance() const -{ - return getData()->getType() == Edge::EDGE_INHERITANCE; -} - -int QtGraphEdge::getZValue(bool active) const -{ - if (isAggregation()) - { - if (active) - { - return -1; - } - return -5; - } - - if (active) - { - return 5; - } - return 1; -} - -float QtGraphEdge::getPenWidth() const -{ - if (isAggregation()) - { - return getAggregationCount() + 1; - } - return 1; -} - -int QtGraphEdge::getAggregationCount() const -{ - if (isAggregation()) - { - return getData()->getComponent()->getAggregationCount(); - } - return 0; -} diff --git a/src/app/qt/view/graphElements/QtGraphEdge.h b/src/app/qt/view/graphElements/QtGraphEdge.h index a6b26b0e..b720b798 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.h +++ b/src/app/qt/view/graphElements/QtGraphEdge.h @@ -10,49 +10,6 @@ #include "component/view/graphElements/GraphEdge.h" class GraphNode; -class QtGraphicsRoundedRectItem; - -class QtStraightConnection - : public QGraphicsLineItem -{ -public: - QtStraightConnection(Vec4i ownerRect, Vec4i targetRect, int number, QGraphicsItem* parent); - virtual ~QtStraightConnection(); - - void setColor(QColor color); - -private: - QtGraphicsRoundedRectItem* m_circle; - QGraphicsSimpleTextItem* m_number; -}; - -class QtCorneredConnection - : public QGraphicsLineItem -{ -public: - QtCorneredConnection(Vec4i ownerRect, Vec4i targetRect, Vec4i ownerParentRect, Vec4i targetParentRect, QGraphicsItem* parent); - virtual ~QtCorneredConnection(); - - virtual QPainterPath shape() const; - virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget); - - void setClosed(bool closed); - void setBig(bool big); - -private: - QPolygon getPath() const; - int getDirection(const QPointF& a, const QPointF& b) const; - - Vec4i m_ownerRect; - Vec4i m_targetRect; - - Vec4i m_ownerParentRect; - Vec4i m_targetParentRect; - - bool m_closed; - bool m_big; -}; - class QtGraphEdge : public QObject @@ -85,13 +42,6 @@ protected: virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event); private: - bool isAggregation() const; - bool isInheritance() const; - - int getZValue(bool active) const; - float getPenWidth() const; - int getAggregationCount() const; - std::weak_ptr m_owner; std::weak_ptr m_target; diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index 1c114358..ec996886 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -7,11 +7,10 @@ #include "utility/messaging/type/MessageActivateTokens.h" #include "utility/messaging/type/MessageGraphNodeMove.h" -#include "qt/graphics/QtGraphicsRoundedRectItem.h" +#include "qt/graphics/QtRoundedRectItem.h" #include "qt/utility/QtDeviceScaledPixmap.h" #include "qt/view/graphElements/nodeComponents/QtGraphNodeComponent.h" #include "qt/view/graphElements/QtGraphEdge.h" -#include "settings/ApplicationSettings.h" void QtGraphNode::blendIn() { @@ -35,36 +34,8 @@ void QtGraphNode::hideNode() QFont QtGraphNode::getFontForNodeType(Node::NodeType type) { - QFont font("Source Code Pro"); - - switch (type) - { - case Node::NODE_UNDEFINED: - case Node::NODE_NAMESPACE: - font.setPixelSize(12); - break; - - case Node::NODE_UNDEFINED_TYPE: - case Node::NODE_STRUCT: - case Node::NODE_CLASS: - case Node::NODE_ENUM: - case Node::NODE_TYPEDEF: - case Node::NODE_TEMPLATE_PARAMETER_TYPE: - case Node::NODE_FILE: - font.setPixelSize(14); - break; - - case Node::NODE_UNDEFINED_FUNCTION: - case Node::NODE_UNDEFINED_VARIABLE: - case Node::NODE_FUNCTION: - case Node::NODE_METHOD: - case Node::NODE_GLOBAL_VARIABLE: - case Node::NODE_FIELD: - case Node::NODE_ENUM_CONSTANT: - font.setPixelSize(11); - break; - } - + QFont font(GraphViewStyle::getFontNameForNodeType(type).c_str()); + font.setPixelSize(GraphViewStyle::getFontSizeForNodeType(type)); return font; } @@ -76,7 +47,7 @@ QtGraphNode::QtGraphNode() { this->setPen(QPen(Qt::transparent)); - m_rect = new QtGraphicsRoundedRectItem(this); + m_rect = new QtRoundedRectItem(this); m_text = new QGraphicsSimpleTextItem(this); } @@ -88,7 +59,7 @@ QtGraphNode::QtGraphNode(const Node* data) { this->setPen(QPen(Qt::transparent)); - m_rect = new QtGraphicsRoundedRectItem(this); + m_rect = new QtRoundedRectItem(this); m_text = new QGraphicsSimpleTextItem(this); this->setAcceptHoverEvents(true); @@ -184,46 +155,22 @@ Vec4i QtGraphNode::getParentBoundingRect() const return node->getBoundingRect(); } -bool QtGraphNode::addOutEdge(const std::shared_ptr& edge) +void QtGraphNode::addOutEdge(const std::shared_ptr& edge) { - // for (std::list>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++) - // { - // if ((*it)->getOwner().lock() == edge->getOwner().lock() && - // (*it)->getTarget().lock() == edge->getTarget().lock()) - // { - // return false; - // } - // } - m_outEdges.push_back(edge); - return true; } -bool QtGraphNode::addInEdge(const std::weak_ptr& edge) +void QtGraphNode::addInEdge(const std::weak_ptr& edge) { - // for (std::list>::iterator it = m_inEdges.begin(); it != m_inEdges.end(); it++) - // { - // std::shared_ptr existingEdge = it->lock(); - // if (existingEdge != NULL) - // { - // if (existingEdge->getOwner().lock() == edge.lock()->getOwner().lock() && - // existingEdge->getTarget().lock() == edge.lock()->getTarget().lock()) - // { - // return false; - // } - // } - // } - m_inEdges.push_back(edge); - return true; } -unsigned int QtGraphNode::getOutEdgeCount() const +size_t QtGraphNode::getOutEdgeCount() const { return m_outEdges.size(); } -unsigned int QtGraphNode::getInEdgeCount() const +size_t QtGraphNode::getInEdgeCount() const { return m_inEdges.size(); } @@ -247,7 +194,7 @@ void QtGraphNode::setIsActive(bool isActive) { m_isActive = isActive; - setStyle(); + updateStyle(); } QtGraphNode* QtGraphNode::getParent() const @@ -281,136 +228,6 @@ void QtGraphNode::addSubNode(const std::shared_ptr& node) m_subNodes.push_back(node); } -void QtGraphNode::setStyle() -{ - if (!m_data) - { - return; - } - - QColor color = Qt::lightGray; - qreal radius = 0.0f; - QPen p(Qt::transparent); - QFont font(getFontForNodeType(m_data->getType())); - - bool useUndefinedPattern = false; - bool useUndefinedColor = false; - - Vec2i padding; - - switch (m_data->getType()) - { - case Node::NODE_UNDEFINED: - p.setStyle(Qt::DashLine); - case Node::NODE_NAMESPACE: - color = Qt::transparent; - - p.setColor("#cc8d91"); - p.setWidth(1); - - radius = 20.0f; - padding.x = 15; - padding.y = 6; - break; - - case Node::NODE_UNDEFINED_TYPE: - useUndefinedPattern = true; - case Node::NODE_STRUCT: - case Node::NODE_CLASS: - case Node::NODE_ENUM: - case Node::NODE_TYPEDEF: - case Node::NODE_TEMPLATE_PARAMETER_TYPE: - case Node::NODE_FILE: - if (m_isActive) - { - font.setWeight(QFont::Bold); - } - - if (m_isHovering) - { - m_rect->setShadow(QColor(0, 0, 0, 255), 5); - } - else - { - m_rect->setShadow(QColor(0, 0, 0, 128), 5); - } - - color = ApplicationSettings::getInstance()->getNodeTypeColor(m_data->getType()).c_str(); - if (m_subNodes.size()) - { - radius = 20.0f; - padding.x = 15; - padding.y = 8; - } - else - { - radius = 10.0f; - padding.x = 8; - padding.y = 4; - } - break; - - case Node::NODE_UNDEFINED_FUNCTION: - case Node::NODE_UNDEFINED_VARIABLE: - useUndefinedPattern = true; - useUndefinedColor = true; - case Node::NODE_FUNCTION: - case Node::NODE_METHOD: - case Node::NODE_GLOBAL_VARIABLE: - case Node::NODE_FIELD: - case Node::NODE_ENUM_CONSTANT: - if (m_isActive || m_isHovering) - { - color = ApplicationSettings::getInstance()->getNodeTypeColor(m_data->getType(), "hover").c_str(); - font.setWeight(QFont::Bold); - } - else - { - color = ApplicationSettings::getInstance()->getNodeTypeColor(m_data->getType()).c_str(); - } - - radius = 8.0f; - padding.x = 5; - padding.y = 3; - break; - } - - if (m_isActive) - { - p.setWidthF(1.5f); - p.setColor("#3c3c3c"); - } - - m_rect->setPen(p); - m_rect->setBrush(QBrush(color)); - m_rect->setRadius(radius); - - if (useUndefinedPattern) - { - QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png"); - pixmap.scaleToHeight(10); - - if (!m_undefinedRect) - { - m_undefinedRect = new QtGraphicsRoundedRectItem(this); - setSize(getSize()); - } - - p.setWidth(1); - p.setColor(Qt::transparent); - if (useUndefinedColor && !m_isActive) - { - p.setColor(color); - } - m_undefinedRect->setPen(p); - m_undefinedRect->setBrush(QBrush(pixmap.pixmap())); - m_undefinedRect->setRadius(radius); - } - - m_text->setFont(font); - m_text->setPos(padding.x, padding.y); -} - void QtGraphNode::setShadowEnabledRecursive(bool enabled) { m_rect->setShadowEnabled(enabled); @@ -440,6 +257,13 @@ void QtGraphNode::hoverEnter() } } +void QtGraphNode::updateStyle() +{ + GraphViewStyle::NodeStyle style = + GraphViewStyle::getStyleForNodeType(m_data->getType(), m_isActive, m_isHovering, m_subNodes.size() > 0); + setStyle(style); +} + void QtGraphNode::mousePressEvent(QGraphicsSceneMouseEvent* event) { event->ignore(); @@ -500,13 +324,13 @@ void QtGraphNode::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) void QtGraphNode::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { m_isHovering = true; - setStyle(); + updateStyle(); } void QtGraphNode::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { m_isHovering = false; - setStyle(); + updateStyle(); } void QtGraphNode::notifyEdgesAfterMove() @@ -530,3 +354,54 @@ void QtGraphNode::notifyEdgesAfterMove() node->notifyEdgesAfterMove(); } } + +void QtGraphNode::setStyle(const GraphViewStyle::NodeStyle& style) +{ + QColor color = style.color.c_str(); + qreal radius = style.cornerRadius; + + QPen p(style.borderColor.c_str()); + p.setWidthF(style.borderWidth); + if (style.borderDashed) + { + p.setStyle(Qt::DashLine); + } + + QFont font(style.fontName.c_str()); + font.setPixelSize(style.fontSize); + if (style.fontBold) + { + font.setWeight(QFont::Bold); + } + + if (style.shadowColor.size()) + { + m_rect->setShadow(style.shadowColor.c_str(), style.shadowBlurRadius); + } + + m_rect->setPen(p); + m_rect->setBrush(QBrush(color)); + m_rect->setRadius(radius); + + if (style.undefinedPattern) + { + QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png"); + pixmap.scaleToHeight(10); + + if (!m_undefinedRect) + { + m_undefinedRect = new QtRoundedRectItem(this); + setSize(getSize()); + } + + p.setWidth(0); + p.setColor(Qt::transparent); + + m_undefinedRect->setPen(p); + m_undefinedRect->setBrush(QBrush(pixmap.pixmap())); + m_undefinedRect->setRadius(radius); + } + + m_text->setFont(font); + m_text->setPos(style.textOffset.x, style.textOffset.y); +} diff --git a/src/app/qt/view/graphElements/QtGraphNode.h b/src/app/qt/view/graphElements/QtGraphNode.h index 05346fe6..00bee876 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.h +++ b/src/app/qt/view/graphElements/QtGraphNode.h @@ -5,9 +5,10 @@ #include #include "component/view/graphElements/GraphNode.h" +#include "component/view/GraphViewStyle.h" class QtGraphEdge; -class QtGraphicsRoundedRectItem; +class QtRoundedRectItem; class QtGraphNodeComponent; class QtGraphNode @@ -49,11 +50,11 @@ public: virtual Vec4i getBoundingRect() const; virtual Vec4i getParentBoundingRect() const; - virtual bool addOutEdge(const std::shared_ptr& edge); - virtual bool addInEdge(const std::weak_ptr& edge); + virtual void addOutEdge(const std::shared_ptr& edge); + virtual void addInEdge(const std::weak_ptr& edge); - virtual unsigned int getOutEdgeCount() const; - virtual unsigned int getInEdgeCount() const; + virtual size_t getOutEdgeCount() const; + virtual size_t getInEdgeCount() const; QSize size() const; void setSize(const QSize& size); @@ -69,12 +70,13 @@ public: std::list> getSubNodes() const; virtual void addSubNode(const std::shared_ptr& node); - void setStyle(); void setShadowEnabledRecursive(bool enabled); virtual void onClick(); void hoverEnter(); + virtual void updateStyle(); + protected: virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); @@ -85,6 +87,8 @@ protected: void notifyEdgesAfterMove(); + void setStyle(const GraphViewStyle::NodeStyle& style); + std::list> m_outEdges; std::list> m_inEdges; @@ -92,8 +96,8 @@ protected: std::list> m_subNodes; QGraphicsSimpleTextItem* m_text; - QtGraphicsRoundedRectItem* m_rect; - QtGraphicsRoundedRectItem* m_undefinedRect; + QtRoundedRectItem* m_rect; + QtRoundedRectItem* m_undefinedRect; Vec2i m_size; diff --git a/src/app/qt/view/graphElements/QtGraphNodeAccess.cpp b/src/app/qt/view/graphElements/QtGraphNodeAccess.cpp index 06a64546..74c8c057 100644 --- a/src/app/qt/view/graphElements/QtGraphNodeAccess.cpp +++ b/src/app/qt/view/graphElements/QtGraphNodeAccess.cpp @@ -6,7 +6,8 @@ #include "utility/messaging/type/MessageGraphNodeExpand.h" -#include "qt/graphics/QtGraphicsRoundedRectItem.h" +#include "component/view/GraphViewStyle.h" +#include "qt/graphics/QtRoundedRectItem.h" #include "qt/utility/QtDeviceScaledPixmap.h" QtGraphNodeAccess::QtAccessToggle::QtAccessToggle(bool expanded, int invisibleSubNodeCount, QGraphicsItem* parent) @@ -28,9 +29,9 @@ QtGraphNodeAccess::QtAccessToggle::QtAccessToggle(bool expanded, int invisibleSu if (invisibleSubNodeCount) { QFont font; - font.setFamily("Myriad Pro"); + font.setFamily(GraphViewStyle::getFontNameOfNumber().c_str()); + font.setPixelSize(GraphViewStyle::getFontSizeOfNumber()); font.setWeight(QFont::Normal); - font.setPixelSize(9); m_number = new QGraphicsSimpleTextItem(this); m_number->setFont(font); @@ -64,20 +65,6 @@ QtGraphNodeAccess::QtGraphNodeAccess( , m_access(accessType) , m_accessIconSize(20) { - Vec2i padding(10, 10); - - QFont font; - font.setFamily("Myriad Pro"); - font.setWeight(QFont::Bold); - font.setPixelSize(11); - font.setCapitalization(QFont::AllUppercase); - m_text->setFont(font); - m_text->setPos(padding.x + m_accessIconSize + 3, padding.y + m_accessIconSize / 2 - 1); - - m_rect->setPen(QPen(Qt::transparent)); - m_rect->setBrush(QBrush(Qt::white)); - m_rect->setRadius(12.0f); - std::string accessString = TokenComponentAccess::getAccessString(accessType); this->setName(accessString); m_text->hide(); @@ -86,8 +73,6 @@ QtGraphNodeAccess::QtGraphNodeAccess( pixmap.scaleToHeight(m_accessIconSize); m_accessIcon = new QGraphicsPixmapItem(pixmap.pixmap(), this); - m_accessIcon->setPos(padding.x, padding.y); - m_accessToggle = new QtAccessToggle(expanded, invisibleSubNodeCount, this); } @@ -128,6 +113,19 @@ void QtGraphNodeAccess::onClick() } } +void QtGraphNodeAccess::updateStyle() +{ + GraphViewStyle::NodeStyle style = GraphViewStyle::getStyleOfAccessNode(); + setStyle(style); + + QFont font = m_text->font(); + font.setCapitalization(QFont::AllUppercase); + m_text->setFont(font); + + m_text->setPos(style.textOffset.x + m_accessIconSize + 3, style.textOffset.y + m_accessIconSize / 2 - 1); + m_accessIcon->setPos(style.textOffset.x, style.textOffset.y); +} + void QtGraphNodeAccess::hideLabel() { m_text->hide(); diff --git a/src/app/qt/view/graphElements/QtGraphNodeAccess.h b/src/app/qt/view/graphElements/QtGraphNodeAccess.h index 6b4e0da5..90022b7e 100644 --- a/src/app/qt/view/graphElements/QtGraphNodeAccess.h +++ b/src/app/qt/view/graphElements/QtGraphNodeAccess.h @@ -30,6 +30,8 @@ public: virtual void addSubNode(const std::shared_ptr& node); virtual void onClick(); + virtual void updateStyle(); + void hideLabel(); private: diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index d2b4db2e..3456de96 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -54,6 +54,9 @@ add_files( component/view/CompositeView.h component/view/GraphView.cpp component/view/GraphView.h + component/view/GraphViewStyle.cpp + component/view/GraphViewStyle.h + component/view/GraphViewStyleImpl.h component/view/MainView.cpp component/view/MainView.h component/view/RefreshView.cpp @@ -264,6 +267,8 @@ add_files( utility/ConfigManager.h utility/Property.h utility/types.h + utility/utility.cpp + utility/utility.h utility/utilityString.cpp utility/utilityString.h utility/Vector.h diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index c5dc9dba..bbf9fe50 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -7,22 +7,10 @@ #include "component/view/graphElements/GraphEdge.h" #include "component/view/graphElements/GraphNode.h" #include "component/view/GraphView.h" +#include "component/view/GraphViewStyle.h" #include "data/access/StorageAccess.h" #include "data/graph/Graph.h" -GraphController::Margins::Margins() - : left(0) - , right(0) - , top(0) - , bottom(0) - , betweenX(0) - , betweenY(0) - , minWidth(0) - , charWidth(0.0f) -{ -} - - GraphController::GraphController(StorageAccess* storageAccess) : m_storageAccess(storageAccess) { @@ -357,11 +345,6 @@ void GraphController::setNodeVisibilityRecursiveTopDown(DummyNode& node) const void GraphController::layoutNesting() { - if (!m_viewMetrics.width) - { - m_viewMetrics = getView()->getViewMetrics(); - } - for (DummyNode& node : m_dummyNodes) { layoutNestingRecursive(node); @@ -370,7 +353,26 @@ void GraphController::layoutNesting() void GraphController::layoutNestingRecursive(DummyNode& node) const { - Margins margins = getMarginsForDummyNode(node); + GraphViewStyle::NodeMargins margins; + + if (node.data) + { + margins = GraphViewStyle::getMarginsForNodeType(node.data->getType(), node.subNodes.size() > 0); + } + else + { + node.invisibleSubNodeCount = 0; + for (const DummyNode& subNode : node.subNodes) + { + if (!subNode.visible) + { + node.invisibleSubNodeCount++; + } + } + + margins = GraphViewStyle::getMarginsOfAccessNode( + node.isExpanded(), node.subNodes.size(), node.invisibleSubNodeCount); + } int y = 0; int x = 0; @@ -410,7 +412,7 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const if (layoutHorizontal) { - x += subNode.size.x + margins.betweenX; + x += subNode.size.x + margins.spacingX; if (subNode.size.y > height) { height = subNode.size.y; @@ -418,7 +420,7 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const } else { - y += subNode.size.y + margins.betweenY; + y += subNode.size.y + margins.spacingY; if (subNode.size.x > width) { width = subNode.size.x; @@ -428,11 +430,11 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const if (x > 0) { - x -= margins.betweenX; + x -= margins.spacingX; } if (y > 0) { - y -= margins.betweenY; + y -= margins.spacingY; } if (layoutHorizontal && x > width) @@ -444,107 +446,6 @@ void GraphController::layoutNestingRecursive(DummyNode& node) const node.size.y = margins.top + y + height + margins.bottom; } -GraphController::Margins GraphController::getMarginsForDummyNode(DummyNode& node) const -{ - Margins margins; - margins.betweenX = margins.betweenY = 8; - - if (node.data) - { - switch (node.data->getType()) - { - case Node::NODE_UNDEFINED: - case Node::NODE_NAMESPACE: - margins.left = margins.right = 15; - margins.top = 28; - margins.bottom = 15; - - margins.charWidth = m_viewMetrics.typeNameCharWidth; - break; - - case Node::NODE_UNDEFINED_TYPE: - case Node::NODE_STRUCT: - case Node::NODE_CLASS: - case Node::NODE_ENUM: - case Node::NODE_TYPEDEF: - case Node::NODE_TEMPLATE_PARAMETER_TYPE: - case Node::NODE_FILE: - if (node.subNodes.size()) - { - margins.left = margins.right = 15; - margins.top = 30; - margins.bottom = 10; - } - else - { - margins.left = margins.right = 8; - margins.top = margins.bottom = 13; - } - - margins.charWidth = m_viewMetrics.typeNameCharWidth; - break; - - case Node::NODE_UNDEFINED_FUNCTION: - case Node::NODE_FUNCTION: - case Node::NODE_METHOD: - margins.left = margins.right = 5; - margins.top = margins.bottom = 10; - - margins.charWidth = m_viewMetrics.functionNameCharWidth; - break; - - case Node::NODE_UNDEFINED_VARIABLE: - case Node::NODE_GLOBAL_VARIABLE: - case Node::NODE_FIELD: - case Node::NODE_ENUM_CONSTANT: - margins.left = margins.right = 5; - margins.top = margins.bottom = 10; - - margins.charWidth = m_viewMetrics.variableNameCharWidth; - break; - } - } - else - { - node.invisibleSubNodeCount = 0; - for (const DummyNode& subNode : node.subNodes) - { - if (!subNode.visible) - { - node.invisibleSubNodeCount++; - } - } - - margins.left = margins.right = 10; - margins.top = 40; - - if (node.invisibleSubNodeCount == node.subNodes.size()) - { - margins.minWidth = 20; - margins.bottom = 10; - } - else - { - margins.minWidth = 82; - - if (node.isExpanded()) - { - margins.bottom = 15; - } - else if (node.invisibleSubNodeCount) - { - margins.bottom = 23; - } - else - { - margins.bottom = 10; - } - } - } - - return margins; -} - DummyNode* GraphController::findDummyNodeRecursive(std::vector& nodes, Id tokenId) { for (DummyNode& node : nodes) diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 644b63b2..c74a0a9a 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -27,23 +27,6 @@ class GraphController , public MessageListener { public: - struct Margins - { - Margins(); - - int left; - int right; - - int top; - int bottom; - - int betweenX; - int betweenY; - - int minWidth; - float charWidth; - }; - GraphController(StorageAccess* storageAccess); ~GraphController(); @@ -70,12 +53,10 @@ private: void layoutNesting(); void layoutNestingRecursive(DummyNode& node) const; - Margins getMarginsForDummyNode(DummyNode& node) const; DummyNode* findDummyNodeRecursive(std::vector& nodes, Id tokenId); DummyNode* findDummyNodeAccessRecursive(std::vector& nodes, Id parentId, TokenComponentAccess::AccessType type); StorageAccess* m_storageAccess; - GraphView::Metrics m_viewMetrics; std::vector m_dummyNodes; std::vector m_dummyEdges; diff --git a/src/lib/component/view/GraphView.cpp b/src/lib/component/view/GraphView.cpp index 265f3da2..e3b3e952 100644 --- a/src/lib/component/view/GraphView.cpp +++ b/src/lib/component/view/GraphView.cpp @@ -1,14 +1,5 @@ #include "component/view/GraphView.h" -GraphView::Metrics::Metrics() - : width(0) - , height(0) - , typeNameCharWidth(0.0f) - , variableNameCharWidth(0.0f) - , functionNameCharWidth(0.0f) -{ -} - GraphView::GraphView(ViewLayout* viewLayout) : View(viewLayout) { diff --git a/src/lib/component/view/GraphView.h b/src/lib/component/view/GraphView.h index cf1c5c2a..b507d337 100644 --- a/src/lib/component/view/GraphView.h +++ b/src/lib/component/view/GraphView.h @@ -4,6 +4,7 @@ #include #include +#include "utility/math/Vector2.h" #include "utility/types.h" #include "component/view/View.h" @@ -15,18 +16,6 @@ class Graph; class GraphView : public View { public: - struct Metrics - { - Metrics(); - - int width; - int height; - - float typeNameCharWidth; - float variableNameCharWidth; - float functionNameCharWidth; - }; - GraphView(ViewLayout* viewLayout); virtual ~GraphView(); @@ -36,7 +25,7 @@ public: std::shared_ptr graph, const std::vector& nodes, const std::vector& edges) = 0; virtual void clear() = 0; - virtual Metrics getViewMetrics() const = 0; + virtual Vec2i getViewSize() const = 0; }; -#endif // GRAPH_VIEW_H \ No newline at end of file +#endif // GRAPH_VIEW_H diff --git a/src/lib/component/view/GraphViewStyle.cpp b/src/lib/component/view/GraphViewStyle.cpp new file mode 100644 index 00000000..6397dd92 --- /dev/null +++ b/src/lib/component/view/GraphViewStyle.cpp @@ -0,0 +1,401 @@ +#include "component/view/GraphViewStyle.h" + +#include "utility/logging/logging.h" + +#include "settings/ApplicationSettings.h" + +GraphViewStyle::NodeMargins::NodeMargins() + : left(0) + , right(0) + , top(0) + , bottom(0) + , spacingX(0) + , spacingY(0) + , minWidth(0) + , charWidth(0.0f) +{ +} + +GraphViewStyle::NodeStyle::NodeStyle() + : shadowBlurRadius(0) + , cornerRadius(0) + , borderWidth(0) + , borderDashed(false) + , fontSize(0) + , fontBold(false) + , undefinedPattern(false) +{ +} + +GraphViewStyle::EdgeStyle::EdgeStyle() + : width(0) + , zValue(0) + , isStraight(false) + , arrowLength(0) + , arrowWidth(0) + , arrowClosed(false) + , cornerRadius(0) + , verticalOffset(0) +{ +} + +std::shared_ptr GraphViewStyle::getImpl() +{ + if (!s_impl) + { + LOG_ERROR("No GraphViewStyleImpl instance set."); + return nullptr; + } + + return s_impl; +} + +void GraphViewStyle::setImpl(std::shared_ptr impl) +{ + s_impl = impl; +} + +float GraphViewStyle::getCharWidthForNodeType(Node::NodeType type) +{ + std::map::const_iterator it = s_charWidths.find(type); + + if (it != s_charWidths.end()) + { + return it->second; + } + + float charWidth = getImpl()->getCharWidthForNodeType(type); + s_charWidths.emplace(type, charWidth); + return charWidth; +} + +size_t GraphViewStyle::getFontSizeForNodeType(Node::NodeType type) +{ + switch (type) + { + case Node::NODE_UNDEFINED: + case Node::NODE_NAMESPACE: + return 12; + + case Node::NODE_UNDEFINED_TYPE: + case Node::NODE_STRUCT: + case Node::NODE_CLASS: + case Node::NODE_ENUM: + case Node::NODE_TYPEDEF: + case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: + return 14; + + case Node::NODE_UNDEFINED_FUNCTION: + case Node::NODE_UNDEFINED_VARIABLE: + case Node::NODE_FUNCTION: + case Node::NODE_METHOD: + case Node::NODE_GLOBAL_VARIABLE: + case Node::NODE_FIELD: + case Node::NODE_ENUM_CONSTANT: + return 11; + } +} + +size_t GraphViewStyle::getFontSizeOfAccessNode() +{ + return 11; +} + +size_t GraphViewStyle::getFontSizeOfNumber() +{ + return 9; +} + +std::string GraphViewStyle::getFontNameForNodeType(Node::NodeType type) +{ + return "Source Code Pro"; +} + +std::string GraphViewStyle::getFontNameOfAccessNode() +{ + return "Myriad Pro"; +} + +std::string GraphViewStyle::getFontNameOfNumber() +{ + return "Myriad Pro"; +} + +GraphViewStyle::NodeMargins GraphViewStyle::getMarginsForNodeType(Node::NodeType type, bool hasChildren) +{ + NodeMargins margins; + margins.spacingX = margins.spacingY = 8; + + switch (type) + { + case Node::NODE_UNDEFINED: + case Node::NODE_NAMESPACE: + margins.left = margins.right = 15; + margins.top = 28; + margins.bottom = 15; + break; + + case Node::NODE_UNDEFINED_TYPE: + case Node::NODE_STRUCT: + case Node::NODE_CLASS: + case Node::NODE_ENUM: + case Node::NODE_TYPEDEF: + case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: + if (hasChildren) + { + margins.left = margins.right = 15; + margins.top = 30; + margins.bottom = 10; + } + else + { + margins.left = margins.right = 8; + margins.top = margins.bottom = 13; + } + break; + + case Node::NODE_UNDEFINED_FUNCTION: + case Node::NODE_FUNCTION: + case Node::NODE_METHOD: + margins.left = margins.right = 5; + margins.top = margins.bottom = 10; + break; + + case Node::NODE_UNDEFINED_VARIABLE: + case Node::NODE_GLOBAL_VARIABLE: + case Node::NODE_FIELD: + case Node::NODE_ENUM_CONSTANT: + margins.left = margins.right = 5; + margins.top = margins.bottom = 10; + break; + } + + margins.charWidth = getCharWidthForNodeType(type); + + return margins; +} + +GraphViewStyle::NodeMargins GraphViewStyle::getMarginsOfAccessNode( + bool expanded, size_t subNodeCount, size_t invisibleSubNodeCount +){ + NodeMargins margins; + margins.spacingX = margins.spacingY = 8; + + margins.left = margins.right = 10; + margins.top = 40; + + if (invisibleSubNodeCount == subNodeCount) + { + margins.minWidth = 20; + margins.bottom = 10; + } + else + { + margins.minWidth = 82; + + if (expanded) + { + margins.bottom = 15; + } + else if (invisibleSubNodeCount) + { + margins.bottom = 23; + } + else + { + margins.bottom = 10; + } + } + + return margins; +} + +GraphViewStyle::NodeStyle GraphViewStyle::getStyleForNodeType( + Node::NodeType type, bool isActive, bool isFocused, bool hasChildren +){ + NodeStyle style; + + style.color = "#D3D3D3"; + style.borderColor = "#00000000"; + + style.fontName = getFontNameForNodeType(type); + style.fontSize = getFontSizeForNodeType(type); + + if (isActive) + { + style.borderColor = "#3c3c3c"; + } + + if (isActive || isFocused) + { + style.color = ApplicationSettings::getInstance()->getNodeTypeColor(type, "hover"); + } + else + { + style.color = ApplicationSettings::getInstance()->getNodeTypeColor(type); + } + + switch (type) + { + case Node::NODE_UNDEFINED: + style.borderDashed = true; + + case Node::NODE_NAMESPACE: + style.borderColor = "#cc8d91"; + style.borderWidth = 1; + + style.cornerRadius = 20; + + style.textOffset.x = 15; + style.textOffset.y = 6; + break; + + case Node::NODE_UNDEFINED_TYPE: + style.undefinedPattern = true; + + case Node::NODE_STRUCT: + case Node::NODE_CLASS: + case Node::NODE_ENUM: + case Node::NODE_TYPEDEF: + case Node::NODE_TEMPLATE_PARAMETER_TYPE: + case Node::NODE_FILE: + if (isActive) + { + style.fontBold = true; + } + + if (isFocused) + { + style.shadowColor = "#FF000000"; + } + else + { + style.shadowColor = "#80000000"; + } + style.shadowBlurRadius = 5; + + if (hasChildren) + { + style.cornerRadius = 20; + style.textOffset.x = 15; + style.textOffset.y = 8; + } + else + { + style.cornerRadius = 10; + style.textOffset.x = 8; + style.textOffset.y = 4; + } + break; + + case Node::NODE_UNDEFINED_FUNCTION: + case Node::NODE_UNDEFINED_VARIABLE: + style.undefinedPattern = true; + + case Node::NODE_FUNCTION: + case Node::NODE_METHOD: + case Node::NODE_GLOBAL_VARIABLE: + case Node::NODE_FIELD: + case Node::NODE_ENUM_CONSTANT: + if (isActive || isFocused) + { + style.fontBold = true; + } + + style.cornerRadius = 8; + style.textOffset.x = 5; + style.textOffset.y = 3; + break; + } + + if (isActive) + { + style.borderWidth = 1.5f; + } + + return style; +} + +GraphViewStyle::NodeStyle GraphViewStyle::getStyleOfAccessNode() +{ + NodeStyle style; + + style.color = "#FFFFFF"; + style.borderColor = "#00000000"; + + style.cornerRadius = 12; + + style.fontName = getFontNameOfAccessNode(); + style.fontSize = getFontSizeOfAccessNode(); + style.fontBold = true; + + style.textOffset.x = 10; + style.textOffset.y = 10; + + return style; +} + +GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused) +{ + EdgeStyle style; + + style.width = isActive ? 2 : 1; + style.zValue = isActive ? 5 : 1; + + style.arrowLength = 5; + style.arrowWidth = 8; + + style.cornerRadius = 10; + style.verticalOffset = 2; + + style.originOffset.x = 17; + style.targetOffset.x = 17; + + style.originOffset.y = -1; + style.targetOffset.y = 1; + + switch (type) + { + case Edge::EDGE_AGGREGATION: + style.isStraight = true; + style.color = isActive ? "#DDD" : "#EEE"; + style.width = 1; + style.zValue = isActive ? -1 : -5; + break; + + case Edge::EDGE_CALL: + style.color = "#F1C100"; + style.originOffset.y = 1; + style.targetOffset.y = -1; + style.verticalOffset = 4; + break; + case Edge::EDGE_USAGE: + style.color = "#62B29D"; + style.originOffset.y = 3; + style.targetOffset.y = -3; + style.verticalOffset = 6; + break; + case Edge::EDGE_INHERITANCE: + style.arrowLength = 15; + style.arrowWidth = 20; + style.arrowClosed = true; + style.targetOffset.x = 29; + case Edge::EDGE_OVERRIDE: + style.color = "#CC5E89"; + break; + case Edge::EDGE_INCLUDE: + style.color = "#87BA50"; + break; + + default: + style.color = "#878787"; + break; + } + + return style; +} + +std::map GraphViewStyle::s_charWidths; +std::shared_ptr GraphViewStyle::s_impl; diff --git a/src/lib/component/view/GraphViewStyle.h b/src/lib/component/view/GraphViewStyle.h new file mode 100644 index 00000000..a74f9b17 --- /dev/null +++ b/src/lib/component/view/GraphViewStyle.h @@ -0,0 +1,103 @@ +#ifndef GRAPH_VIEW_STYLE_H +#define GRAPH_VIEW_STYLE_H + +#include +#include + +#include "component/view/graphElements/GraphNode.h" +#include "component/view/GraphViewStyleImpl.h" +#include "data/graph/Node.h" + +class GraphViewStyle +{ +public: + struct NodeMargins + { + NodeMargins(); + + int left; + int right; + + int top; + int bottom; + + int spacingX; + int spacingY; + + int minWidth; + float charWidth; + }; + + struct NodeStyle + { + NodeStyle(); + + std::string color; + + std::string shadowColor; + int shadowBlurRadius; + + int cornerRadius; + + float borderWidth; + std::string borderColor; + bool borderDashed; + + std::string fontName; + size_t fontSize; + bool fontBold; + + Vec2i textOffset; + + bool undefinedPattern; + }; + + struct EdgeStyle + { + EdgeStyle(); + + std::string color; + + float width; + int zValue; + + bool isStraight; + + int arrowLength; + int arrowWidth; + bool arrowClosed; + + int cornerRadius; + int verticalOffset; + + Vec2i originOffset; + Vec2i targetOffset; + }; + + static std::shared_ptr getImpl(); + static void setImpl(std::shared_ptr impl); + + static float getCharWidthForNodeType(Node::NodeType type); + + static size_t getFontSizeForNodeType(Node::NodeType type); + static size_t getFontSizeOfAccessNode(); + static size_t getFontSizeOfNumber(); + + static std::string getFontNameForNodeType(Node::NodeType type); + static std::string getFontNameOfAccessNode(); + static std::string getFontNameOfNumber(); + + static NodeMargins getMarginsForNodeType(Node::NodeType type, bool hasChildren); + static NodeMargins getMarginsOfAccessNode(bool expanded, size_t subNodeCount, size_t invisibleSubNodeCount); + + static NodeStyle getStyleForNodeType(Node::NodeType type, bool isActive, bool isFocused, bool hasChildren); + static NodeStyle getStyleOfAccessNode(); + + static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused); + +private: + static std::map s_charWidths; + static std::shared_ptr s_impl; +}; + +#endif // GRAPH_VIEW_STYLE_H diff --git a/src/lib/component/view/GraphViewStyleImpl.h b/src/lib/component/view/GraphViewStyleImpl.h new file mode 100644 index 00000000..818bdfd8 --- /dev/null +++ b/src/lib/component/view/GraphViewStyleImpl.h @@ -0,0 +1,12 @@ +#ifndef GRAPH_VIEW_STYLE_IMPL_H +#define GRAPH_VIEW_STYLE_IMPL_H + +#include "data/graph/Node.h" + +class GraphViewStyleImpl +{ +public: + virtual float getCharWidthForNodeType(Node::NodeType type) = 0; +}; + +#endif // GRAPH_VIEW_STYLE_IMPL_H diff --git a/src/lib/component/view/graphElements/GraphNode.h b/src/lib/component/view/graphElements/GraphNode.h index 8fac1504..bb62aa07 100644 --- a/src/lib/component/view/graphElements/GraphNode.h +++ b/src/lib/component/view/graphElements/GraphNode.h @@ -37,11 +37,11 @@ public: virtual Vec4i getBoundingRect() const = 0; virtual Vec4i getParentBoundingRect() const = 0; - virtual bool addOutEdge(const std::shared_ptr& edge) = 0; - virtual bool addInEdge(const std::weak_ptr& edge) = 0; + virtual void addOutEdge(const std::shared_ptr& edge) = 0; + virtual void addInEdge(const std::weak_ptr& edge) = 0; - virtual unsigned int getOutEdgeCount() const = 0; - virtual unsigned int getInEdgeCount() const = 0; + virtual size_t getOutEdgeCount() const = 0; + virtual size_t getInEdgeCount() const = 0; protected: const Node* m_data; diff --git a/src/lib/utility/utility.cpp b/src/lib/utility/utility.cpp new file mode 100644 index 00000000..18c9eb47 --- /dev/null +++ b/src/lib/utility/utility.cpp @@ -0,0 +1,35 @@ +#include "utility/utility.h" + +float utility::duration(std::function func) +{ + std::chrono::time_point start = std::chrono::system_clock::now(); + + func(); + + std::chrono::duration duration = + std::chrono::duration_cast(std::chrono::system_clock::now() - start); + return duration.count(); +} + +bool utility::intersectionPoint(Vec2f a1, Vec2f b1, Vec2f a2, Vec2f b2, Vec2f* i) +{ + Vec2f p = a1; + Vec2f v = b1 - a1; + Vec2f q = a2; + Vec2f w = b2 - a2; + + float denominator = v.x * w.y - v.y * w.x; + if (denominator != 0) + { + float t = (p.y * w.x - p.x * w.y + q.x * w.y - q.y * w.x) / denominator; + float s = (q.y * v.x - q.x * v.y + p.x * v.y - p.y * v.x) / -denominator; + + if (t >= 0 && t <= 1 && s >= 0 && s <= 1) + { + *i = p + v * t; + return true; + } + } + + return false; +} diff --git a/src/lib/utility/utility.h b/src/lib/utility/utility.h index 8fb3d54c..785b7b7a 100644 --- a/src/lib/utility/utility.h +++ b/src/lib/utility/utility.h @@ -2,40 +2,45 @@ #define UTILITY_H #include +#include + +#include "utility/math/Vector2.h" namespace utility { - float duration(std::function func) - { - std::chrono::time_point start = std::chrono::system_clock::now(); - - func(); - - std::chrono::duration duration = - std::chrono::duration_cast(std::chrono::system_clock::now() - start); - return duration.count(); - } + float duration(std::function func); template - std::vector concat(const std::vector& a, const std::vector& b) - { - std::vector r(a.size() + b.size()); - append(r, a); - append(r, b); - return r; - } + std::vector concat(const std::vector& a, const std::vector& b); template - void append(std::vector& a, const std::vector& b) - { - a.insert(a.begin(), b.begin(), b.end()); - } + void append(std::vector& a, const std::vector& b); template - void append(std::set& a, const std::set& b) - { - a.insert(b.begin(), b.end()); - } + void append(std::set& a, const std::set& b); + + bool intersectionPoint(Vec2f a1, Vec2f b1, Vec2f a2, Vec2f b2, Vec2f* i); +} + +template +std::vector utility::concat(const std::vector& a, const std::vector& b) +{ + std::vector r(a.size() + b.size()); + append(r, a); + append(r, b); + return r; +} + +template +void utility::append(std::vector& a, const std::vector& b) +{ + a.insert(a.begin(), b.begin(), b.end()); +} + +template +void utility::append(std::set& a, const std::set& b) +{ + a.insert(b.begin(), b.end()); } #endif // UTILITY_H