bool ClassDiagram::loadDiagram(File &file) { NameValueFile nameValFile; bool success = nameValFile.readFile(file); if(success) { CompoundValue names; names.parseString(nameValFile.getValue("Names")); CompoundValue xPositions; xPositions.parseString(nameValFile.getValue("XPositions")); CompoundValue yPositions; yPositions.parseString(nameValFile.getValue("YPositions")); std::vector<ClassNode> &nodes = getNodes(); for(size_t i=0; i<names.size(); i++) { OovString name = names[i]; if(i == 0) { // The node at index zero is the graph key, and is not stored in // the graph with a name or type. // The node at index one is the first class, which is typically the // same as the drawing name. eDiagramStorageTypes drawingType; OovString drawingName; DiagramStorage::getDrawingHeader(nameValFile, drawingType, drawingName); // This adds the key automatically as item index zero. // Call this function to set the last selected class name for the journal. clearGraphAndAddClass(drawingName, ClassGraph::AN_All, ClassDiagram::DEPTH_SINGLE_CLASS, false); int x=0; int y=0; xPositions[i].getInt(0, INT_MAX, x); yPositions[i].getInt(0, INT_MAX, y); nodes[0].setPosition(GraphPoint(x, y)); } else { // This will not add duplicates, so if the name is different // from the drawingName, it will be added. addClass(name, ClassGraph::AN_All, ClassDiagram::DEPTH_SINGLE_CLASS, false); } auto nodeIter = std::find_if(nodes.begin(), nodes.end(), [&name](ClassNode &node) { return(node.getType() && name == node.getType()->getName()); }); if(nodeIter != nodes.end()) { int x=0; int y=0; xPositions[i].getInt(0, INT_MAX, x); yPositions[i].getInt(0, INT_MAX, y); nodeIter->setPosition(GraphPoint(x, y)); } } } return success; }
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 ComponentDiagramView::buttonReleaseEvent(const GdkEventButton *event) { if(event->button == 1) { ComponentNode *node = mComponentDiagram.getNode( gStartPosInfo.x, gStartPosInfo.y); if(node) { GraphPoint offset = gStartPosInfo; offset.sub(node->getRect().start); GraphPoint newPos = GraphPoint(static_cast<int>(event->x), static_cast<int>(event->y)); newPos.sub(offset); node->setPos(newPos); mComponentDiagram.setModified(); drawToDrawingArea(); } } else { displayContextMenu(event->button, event->time, (gpointer)event); } }
void Graph::AddReading(double value) { Lock(); double now = time(NULL); for(int s=0; s<DataSets.size(); s++) { GraphDataSet* dataSet = DataSets[s]; if (dataSet->Points.Count == 0 || now >= dataSet->LastTime + dataSet->TimeStep) { dataSet->Points.Add(GraphPoint(now, value, value)); dataSet->LastTime = now; } else { GraphPoint* point = dataSet->Points.PeekNewest(); if (value < point->MinValue) point->MinValue = value; if (value > point->MaxValue) point->MaxValue = value; } dataSet->MinValue = dataSet->MaxValue = value; for(int i=0; i<dataSet->Points.Count; i++) { GraphPoint* point = dataSet->Points.Get(i); if (point->MinValue < dataSet->MinValue) dataSet->MinValue = point->MinValue; if (point->MaxValue > dataSet->MaxValue) dataSet->MaxValue = point->MaxValue; } dataSet->DeltaValue = dataSet->MaxValue - dataSet->MinValue; } Unlock(); }
// This replicates the right side block to the left side, from bottom to top. void BlockPolygon::finishBlock() { int rightSize = static_cast<int>(size()); for(int i=rightSize-1; i>=0; i--) { push_back(GraphPoint(mCenterLineX - (at(static_cast<size_t>(i)).x - mCenterLineX), at(static_cast<size_t>(i)).y)); } }
ComponentNode *ComponentGraph::getNode(int x, int y) { ComponentNode *node = nullptr; for(size_t i=0; i<mNodes.size(); i++) { if(mNodes[i].getRect().isPointIn(GraphPoint(x, y))) node = &mNodes[i]; } return node; }
ClassNode *ClassGraph::getNode(int x, int y) { ClassNode *node = nullptr; for(size_t i=0; i<mNodes.size(); i++) { GraphRect rect = mNodes[i].getRect(); if(rect.isPointIn(GraphPoint(x, y))) node = &mNodes[i]; } return node; }
void GraphLines::setPoint(float value) { setPointLock.lock(); if (currentMaxYValue < value) { yValueChange(value); } if (m_graphPoints.size() > MAXIMUM_GRAPH_POINTS) { m_graphPoints.erase(m_graphPoints.begin(), m_graphPoints.begin() + (m_graphPoints.size() - MAXIMUM_GRAPH_POINTS)); } m_graphPoints.push_back(GraphPoint(screenHeight - (screenHeight * ((100.0 / currentMaxYValue * value) / 100.0)) + 50, value)); setPointLock.unlock(); }
void ZoneDiagramView::handleDrawingAreaMotion(int x, int y) { const ZoneNode *node = getDiagram().getZoneNode(GraphPoint(x, y)); if(node) { std::string str = "Class name: "; str += node->mType->getName(); str += "\nComponent name: "; str += node->mType->getClass()->getModule()->getName(); mToolTipWindow.handleCursorMovement(x, y, str); } else { mToolTipWindow.hide(); } }
void ZoneDiagramView::graphButtonReleaseEvent(const GdkEventButton *event) { if(event->button == 1) { ZoneNode const *node = mZoneDiagram.getZoneNode(sStartPosInfo); if(node) { mZoneDiagram.setPosition(node, sStartPosInfo, GraphPoint(event->x, event->y)); updateGraphAndRequestRedraw(); } } else { graphDisplayContextMenu(event->button, event->time, (gpointer)event); } }
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; } } }
void PortionDiagramView::graphButtonReleaseEvent(const GdkEventButton *event) { if(event->button == 1) { size_t nodeIndex = mPortionDiagram.getNodeIndex(mNullDrawer, sStartPosInfo); if(nodeIndex != PortionDrawer::NO_INDEX) { mPortionDiagram.setPosition(nodeIndex, sStartPosInfo, GraphPoint(event->x, event->y)); requestRedraw(); } } else { portionGraphDisplayContextMenu(event->button, event->time, (gpointer)event); } }
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); }
// This only stores points for the right side of the blocks. void BlockPolygon::decDepth(int y) { push_back(GraphPoint(mCenterLineX + mDepth*mPad, y)); push_back(GraphPoint(mCenterLineX + --mDepth*mPad, y)); }