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