void PortionDrawer::drawConnections(DiagramDrawer &drawer) { size_t lastColorIndex = NO_INDEX; for(auto const &conn : mGraph->getConnections()) { GraphRect suppRect = getNodeRect(drawer, conn.mSupplierNodeIndex); GraphRect consRect = getNodeRect(drawer, conn.mConsumerNodeIndex); GraphPoint suppPoint; GraphPoint consPoint; drawer.getConnectionPoints(consRect, suppRect, consPoint, suppPoint); size_t colorIndex = conn.mSupplierNodeIndex; if(colorIndex != lastColorIndex) { if(lastColorIndex != NO_INDEX) { drawer.groupShapes(false, 0, 0); } Color lineColor = DistinctColors::getColor(colorIndex % DistinctColors::getNumColors()); drawer.groupShapes(true, lineColor, Color(245,245,255)); lastColorIndex = colorIndex; } drawArrowDependency(drawer, consPoint, suppPoint); } if(lastColorIndex != NO_INDEX) { drawer.groupShapes(false, 0, 0); } }
GraphSize OperationDrawer::drawOperation(DiagramDrawer &drawer, GraphPoint pos, OperationDefinition &operDef, const OperationGraph &graph, const OperationDrawOptions &options, std::set<const OperationDefinition*> &drawnOperations, bool draw) { std::vector<DrawString> drawStrings; if(draw) { drawer.groupShapes(true, Color(0,0,0), Color(245,245,255)); } GraphSize size = drawOperationNoText(drawer, pos, operDef, graph, options, drawnOperations, drawStrings, draw); if(draw) { drawer.groupShapes(false, Color(0,0,0), Color(245,245,255)); drawer.groupText(true, false); for(size_t i=0; i<drawStrings.size(); i++) { drawer.drawText(drawStrings[i].pos, drawStrings[i].str); } drawer.groupText(false, false); } return size; }
GraphSize OperationDrawer::drawDiagram(DiagramDrawer &drawer, OperationGraph &graph, const OperationDrawOptions &options) { drawer.setDiagramSize(getDrawingSize(drawer, graph, options)); drawer.setCurrentDrawingFontSize(mDiagram.getDiagramBaseFontSize()); return drawOrSizeDiagram(drawer, graph, options, true); }
static void drawCall(DiagramDrawer &drawer, GraphPoint source, GraphPoint target, bool isConst, int arrowLen) { drawer.drawLine(source, target, isConst); // Draw arrow if(source.x > target.x) arrowLen = -arrowLen; drawer.drawLine(GraphPoint(target.x-arrowLen, target.y-arrowLen), GraphPoint(target.x, target.y)); drawer.drawLine(GraphPoint(target.x-arrowLen, target.y+arrowLen), GraphPoint(target.x, target.y)); }
void OperationDrawer::drawLifeLines(DiagramDrawer &drawer, const std::vector<OperationClass> &classes, std::vector<int> const &classEndY, int endy) { drawer.groupShapes(true, Color(0,0,0), Color(245,245,255)); endy += mCharHeight; for(size_t i=0; i<classes.size(); i++) { const auto &cl = classes[i]; int x = cl.getLifelinePosX(); drawer.drawLine(GraphPoint(x, classEndY[i]), GraphPoint(x, endy)); } drawer.groupShapes(false, Color(0,0,0), Color(245,245,255)); }
void PortionDrawer::updateNodePositions(DiagramDrawer &drawer) { if(mGraph) { if(mGraph->getNodes().size() != mNodePositions.size()) { mNodePositions.resize(mGraph->getNodes().size()); } std::vector<size_t> depths = getCallDepths(); std::vector<int> columnPositions = getColumnPositions(drawer, depths); int yOffset = 0; const int margin = 20; int pad = static_cast<int>(drawer.getTextExtentHeight("W")); for(size_t i=0; i<mNodePositions.size(); i++) { GraphRect rect = getNodeRect(drawer, i); rect.start.y = yOffset; yOffset += pad + rect.size.y; rect.start.y += margin; rect.start.x = margin + columnPositions[depths[i]]; mNodePositions[i] = rect.start; } } #define PORTION_GENES 1 #if(PORTION_GENES) if(mNodePositions.size() > 0) { DiagramDependencyGenes genes; GraphRect rect = getNodeRect(drawer, 0); genes.initialize(*this, static_cast<size_t>(rect.size.y)); genes.updatePositionsInDrawer(); } #endif }
void PortionDrawer::drawGraph(DiagramDrawer &drawer) { if(mGraph) { // This must be set for svg drawer.setDiagramSize(getDrawingSize(drawer)); drawNodes(drawer); drawer.groupShapes(true, Color(0,0,0), Color(245,245,255)); drawConnections(drawer); drawer.groupShapes(false, 0, 0); std::vector<DrawString> drawStrings; std::vector<bool> virtOpers; getNodeText(drawer, drawStrings, virtOpers); drawer.groupText(true, false); drawNodeText(drawer, false, drawStrings, virtOpers); drawer.groupText(false, false); drawer.groupText(true, true); drawNodeText(drawer, true, drawStrings, virtOpers); drawer.groupText(false, false); } }
void PortionDrawer::drawNodes(DiagramDrawer &drawer) { drawer.groupShapes(true, Color(0,0,0), Color(245,245,255)); for(size_t i=0; i<mNodePositions.size(); i++) { if(mGraph->getNodes()[i].getNodeType() == PNT_Attribute) { drawer.drawRect(getNodeRect(drawer, i)); } else { drawer.drawEllipse(getNodeRect(drawer, i)); } } drawer.groupShapes(false, 0, 0); drawer.groupShapes(true, Color(0,0,255), Color(245,245,255)); for(size_t i=0; i<mNodePositions.size(); i++) { if(mGraph->getNodes()[i].getNodeType() == PNT_NonMemberVariable) { drawer.drawRect(getNodeRect(drawer, i)); } } drawer.groupShapes(false, 0, 0); }
void PortionDrawer::drawNodeText(DiagramDrawer &drawer, bool drawVirts, std::vector<DrawString> const &drawStrings, std::vector<bool> const &virtOpers) { for(size_t i=0; i<drawStrings.size(); i++) { if(drawVirts == virtOpers[i]) { drawer.drawText(drawStrings[i].pos, drawStrings[i].str); } } }
GraphSize OperationDrawer::drawOrSizeDiagram(DiagramDrawer &drawer, OperationGraph &graph, const OperationDrawOptions &options, bool draw) { mCharHeight = static_cast<int>(drawer.getTextExtentHeight("W")); int pad = mCharHeight / 3; if(pad < 1) pad = 1; mPad = pad; GraphPoint startpos(mCharHeight, mCharHeight); GraphPoint pos = startpos; GraphSize size; GraphSize diagramSize; int maxy = 0; std::vector<int> classEndY; for(size_t i=0; i<graph.mOpClasses.size(); i++) { OperationClass &opClass = graph.mOpClasses[i]; opClass.setPosition(pos); size = drawClass(drawer, opClass, options, draw); size_t condDepth = graph.getNestDepth(i); size.x += static_cast<int>(condDepth) * mPad; opClass.setSize(size); pos.x += size.x + mCharHeight; classEndY.push_back(startpos.y + size.y); if(size.y > maxy) maxy = size.y; } diagramSize.x = pos.x; pos = startpos; pos.y = startpos.y + maxy; // space between class rect and operations std::set<const OperationDefinition*> drawnOperations; for(const auto &oper : graph.mOperations) { if(drawnOperations.find(oper) == drawnOperations.end()) { size = drawOperation(drawer, pos, *oper, graph, options, drawnOperations, draw); pos.y += size.y; } } if(draw) { drawLifeLines(drawer, graph.mOpClasses, classEndY, pos.y); } diagramSize.y = pos.y + mCharHeight; return diagramSize; }
void PortionDrawer::getNodeText(DiagramDrawer &drawer, std::vector<DrawString> &drawStrings, std::vector<bool> &virtOpers) { float textHeight = drawer.getTextExtentHeight("W"); int pad = static_cast<int>(textHeight / 7.f * 2); int yTextOffset = static_cast<int>(textHeight) + pad; for(size_t i=0; i<mGraph->getNodes().size(); i++) { GraphRect rect = getNodeRect(drawer, i); rect.start.x += pad; rect.start.y += yTextOffset; PortionNode const &node = mGraph->getNodes()[i]; drawStrings.push_back(DrawString(rect.start, node.getDisplayName().getStr())); virtOpers.push_back(node.isVirtualOperation()); } }
void ComponentDiagram::updatePositionsInGraph(DiagramDrawer &nullDrawer) { ComponentDrawer drawer(*this, nullDrawer); int pad = nullDrawer.getPad(1) * 2; enum NodeVectorsIndex { NVI_ExtPackage, NVI_Lib, NVI_Exec, NVI_NumVecs }; NodeVectors nodeVectors[NVI_NumVecs]; int nodeSpacingY = 0; for(auto &node : mComponentGraph.getNodes()) { GraphSize size = drawer.drawNode(node); node.setSize(size); if(nodeSpacingY == 0) nodeSpacingY = size.y * 2; if(node.getComponentNodeType() == ComponentNode::CNT_ExternalPackage) { nodeVectors[NVI_ExtPackage].add(&node, size.x, pad); } else { if(node.getComponentType() == ComponentTypesFile::CT_StaticLib) { nodeVectors[NVI_Lib].add(&node, size.x, pad); } else { nodeVectors[NVI_Exec].add(&node, size.x, pad); } } } int biggestX = 0; for(auto const &vec : nodeVectors) { if(vec.nodesSizeX > biggestX) biggestX = vec.nodesSizeX; } for(size_t veci=0; veci<sizeof(nodeVectors)/sizeof(nodeVectors[0]); veci++) { int yPos = static_cast<int>(veci) * nodeSpacingY; int xPos = (biggestX - static_cast<int>(nodeVectors[veci].nodesSizeX)) / 2; for(auto const &node : nodeVectors[veci].nodeVector) { node->setPos(GraphPoint(xPos, yPos)); xPos += node->getRect().size.x + pad; } } }
GraphSize OperationDrawer::drawClass(DiagramDrawer &drawer, const OperationClass &node, const OperationDrawOptions & /*options*/, bool draw) { GraphPoint startpos = node.getPosition(); const ModelType *type = node.getType(); OovStringRef const typeName = type->getName(); int rectx = 0; int recty = 0; const ModelClassifier *classifier = type->getClass(); if(classifier) { if(draw) { drawer.groupText(true, false); } OovStringVec strs; std::vector<GraphPoint> positions; strs.push_back(typeName); splitStrings(strs, 30, 40); for(auto const &str : strs) { recty += mCharHeight + (mPad * 2); positions.push_back(GraphPoint(startpos.x+mPad, startpos.y + recty - mPad)); int curx = static_cast<int>(drawer.getTextExtentWidth(str)) + mPad*2; if(curx > rectx) rectx = curx; } if(draw) { drawer.groupShapes(true, Color(0,0,0), Color(245,245,255)); drawer.drawRect(GraphRect(startpos.x, startpos.y, rectx, recty)); drawer.groupShapes(false, Color(0,0,0), Color(245,245,255)); for(size_t i=0; i<strs.size(); i++) { drawer.drawText(positions[i], strs[i]); } drawer.groupText(false, false); } } return GraphSize(rectx, recty); }
GraphSize OperationDrawer::drawOperationNoText(DiagramDrawer &drawer, GraphPoint pos, OperationDefinition &operDef, const OperationGraph &graph, const OperationDrawOptions &options, std::set<const OperationDefinition*> &drawnOperations, std::vector<DrawString> &drawStrings, bool draw, int callDepth) { GraphPoint startpos = pos; // Add space between bottom of class and operation name int starty = startpos.y+(mPad*2); int y=starty; size_t sourceIndex = operDef.getOperClassIndex(); int arrowLen = mCharHeight * 7 / 10; std::vector<int> condStartPosY; drawnOperations.insert(&operDef); const OperationClass &cls = graph.getClass(sourceIndex); if(callDepth == 0) { // Reinit all polys to initial conditions. mLifelinePolygons.clear(); mLifelinePolygons.resize(graph.getClasses().size()); } BlockPolygon &poly = mLifelinePolygons[sourceIndex]; poly.setup(cls.getLifelinePosX(), mPad); if(!graph.isOperCalled(operDef)) { // Show starting operation operDef.setRect(GraphPoint(cls.getPosition().x, y), GraphSize(mCharHeight*50, mCharHeight+mPad)); y += mCharHeight; drawStrings.push_back(DrawString(GraphPoint( cls.getPosition().x, y), operDef.getName())); // Add space between operation name and called operations. y += (mPad * 2); int lineY = y + mPad*2; if(draw) { drawCall(drawer, GraphPoint(cls.getPosition().x, lineY), GraphPoint(cls.getLifelinePosX(), lineY), operDef.isConst(), arrowLen); } } for(const auto &stmt : operDef.getStatements()) { int condOffset = poly.getDepth() * mPad; switch(stmt->getStatementType()) { case ST_Call: { OperationCall *call = stmt->getCall(); size_t targetIndex = call->getOperClassIndex(); int lineY = y + mCharHeight + mPad*2; int sourcex = cls.getLifelinePosX(); sourcex += condOffset; const OperationClass &targetCls = graph.getClass(targetIndex); int targetx = targetCls.getLifelinePosX(); if(targetIndex == NO_INDEX) { // Handle [else] // int len = mCharHeight*3; // mDrawer.drawLine(GraphPoint(sourcex, lineY), // GraphPoint(sourcex+len, lineY), call->isConst()); } else if(targetIndex != sourceIndex) { if(draw) { drawCall(drawer, GraphPoint(sourcex, lineY), GraphPoint(targetx, lineY), call->isConst(), arrowLen); } } else { // Draw line back to same class int len = mCharHeight*3; int height = 3; if(draw) { drawer.drawLine(GraphPoint(sourcex, lineY), GraphPoint(sourcex+len, lineY), call->isConst()); drawer.drawLine(GraphPoint(sourcex+len, lineY), GraphPoint(sourcex+len, lineY+height)); drawer.drawLine(GraphPoint(sourcex, lineY+height), GraphPoint(sourcex+len, lineY+height), call->isConst()); } y += height; } int textX = (sourceIndex < targetIndex) ? cls.getLifelinePosX() : targetCls.getLifelinePosX(); GraphPoint callPos(textX+condOffset+mPad, y+mCharHeight); drawStrings.push_back(DrawString(callPos, call->getName())); call->setRect(GraphPoint(callPos.x, callPos.y-mCharHeight), GraphSize(mCharHeight*50, mCharHeight+mPad)); y += mCharHeight*2; // Draw child definition. OperationDefinition *childDef = graph.getOperDefinition(*call); if(childDef) { // poly.startChildBlock(condDepth, y); if(drawnOperations.find(childDef) == drawnOperations.end()) { poly.incDepth(y); GraphSize childSize = drawOperationNoText(drawer, GraphPoint(pos.x, y), *childDef, graph, options, drawnOperations, drawStrings, draw, callDepth+1); y += childSize.y + mPad * 2; poly.decDepth(y); } else { // This draws a rectangle to signify that it is defined // elsewhere in the diagram. GraphRect rect(targetx + mPad*2, callPos.y + mPad*2, mCharHeight+mPad, mCharHeight+mPad); if(draw) { drawer.drawRect(rect); } y += mCharHeight+mPad; } // poly.endChildBlock(condDepth, y); } } break; case ST_VarRef: { OperationVarRef *ref = stmt->getVarRef(); size_t targetIndex = ref->getOperClassIndex(); int lineY = y + mCharHeight + mPad*2; int sourcex = cls.getLifelinePosX(); sourcex += condOffset; const OperationClass &targetCls = graph.getClass(targetIndex); int targetx = targetCls.getLifelinePosX(); if(targetIndex == NO_INDEX) { int len = mCharHeight*3; if(draw) { drawer.drawLine(GraphPoint(sourcex, lineY), GraphPoint(sourcex+len, lineY), ref->isConst()); } } else if(targetIndex != sourceIndex) { if(draw) { drawCall(drawer, GraphPoint(sourcex, lineY), GraphPoint(targetx, lineY), ref->isConst(), arrowLen); } } else { // Draw line back to same class int len = mCharHeight*3; int height = 3; if(draw) { drawer.drawLine(GraphPoint(sourcex, lineY), GraphPoint(sourcex+len, lineY), ref->isConst()); drawer.drawLine(GraphPoint(sourcex+len, lineY), GraphPoint(sourcex+len, lineY+height)); drawer.drawLine(GraphPoint(sourcex, lineY+height), GraphPoint(sourcex+len, lineY+height), ref->isConst()); } y += height; } int textX = (sourceIndex < targetIndex) ? cls.getLifelinePosX() : targetCls.getLifelinePosX(); GraphPoint callPos(textX+condOffset+mPad, y+mCharHeight); if(draw) { drawStrings.push_back(DrawString(callPos, ref->getName())); } ref->setRect(GraphPoint(callPos.x, callPos.y-mCharHeight), GraphSize(mCharHeight*50, mCharHeight+mPad)); y += mCharHeight*2; } break; case ST_OpenNest: { GraphPoint lifePos(cls.getLifelinePosX()+condOffset+ mPad, y+mCharHeight); const OperationNestStart *cond = stmt->getNestStart(); if(draw) { drawStrings.push_back(DrawString(lifePos, cond->getExpr())); } condStartPosY.push_back(y); y += mCharHeight*2; poly.incDepth(y); } break; case ST_CloseNest: { poly.decDepth(y); } break; } } if(callDepth == 0) { for(auto &poly : mLifelinePolygons) { poly.finishBlock(); if(draw) { drawer.drawPoly(poly, Color(245,245,255)); } } } return GraphSize(0, y - startpos.y); }