Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

Graph.h

Go to the documentation of this file.
00001 //345678901234567890123456789012345678901234567890123456789012345678901234567890
00002 // Graph.h
00003 //
00004 // Graph can be used to show a graph that can optionally be zoomed and panned.
00005 //
00006 // As nodes a Graph can accept any drawable object that implements the
00007 //      SetGetDimensions2dIntI
00008 // interface class, which defines the following two member functions:
00009 //      virtual void GetDimensions(int& x, int& y, int& w, int& h) = 0;
00010 //      virtual void SetDimensions(int x, int y, int w, int h) = 0;
00011 //
00012 // OglGui::Window as well as OglGui::View implement the SetGetDimensions2dIntI
00013 // interface class. Therefore, any OglGui::Window derived OGL component as
00014 // well as any OglGui::View derived view can be added as nodes to a Graph.
00015 //
00016 // Such nodes are first created in the normal way inside the graph, after which
00017 // the graph needs to be informed about items added.
00018 // Exampe:
00019 //      Graph*  graph = new Graph(parent, 10, 10, 400, 400);
00020 //      Window* wnd   = new Window(graph, 100, 100, 40, 40);
00021 //      View*   view  = new View(graph, imPtr, 200, 200, 100, 100);
00022 //      graph->AddNode(wnd);
00023 //      graph->AddNode(view);
00024 //      // Connect nodes 'wnd' to 'view' with a line going from RED to BLUE
00025 //      graph->ConnectNode(wnd, view, oglRED, oglBLUE);
00026 //
00027 // Since a Graph itself is also derived from OglGui::window, it can also
00028 // be added as a node, that is optionally sizable, inside another graph.
00029 // When serving as a simple node you can let it show a text and ask it to
00030 // draw a rectangle or an oval, of which the (possibly transparent) background
00031 // can be set.
00032 //
00033 // ToDo: Add code for node removal.
00034 //
00035 // Author: Richard van Balen
00036 #ifndef OglGui_Graph_h
00037 #define OglGui_Graph_h
00038 
00039 #ifndef OglGui_DocDimensions_h
00040 #include "OglGui/DocDimensions.h"
00041 #endif
00042 
00043 #ifndef OglGui_SizableWindow_h
00044 #include "OglGui/SizableWindow.h"
00045 #endif
00046 
00047 /*
00048 #ifndef OglGui_View_h
00049 #include "OglGui/View.h"
00050 #endif
00051 */
00052 
00053 namespace OglGui {
00054 
00055 class Graph : public SizableWindow, public DocDimensions
00056 {
00057 public:
00058     typedef SetGetDimensions2dIntI          Node;
00059     typedef std::vector<Node*>              NodeVector;
00060     typedef std::vector<ULONG>              ColorVector;
00061 
00062     // Info on the nodes inside a graph
00063     struct NodeInfo {
00064         NodeVector  nodeVector;      // First element is the node itself,
00065                                      // followed by the nodes it connects to
00066         ColorVector lineStartColors; // Connecting line start colors
00067         ColorVector lineEndColors;   // Connecting line end colors
00068         Graph*      graphPtr;        // Non-null when the node is a graph
00069         int         scaleMode;       // Scale constraints. 0 = no constraints
00070                                      // NoWidth,NoHeight,NoHorizontal,NoVertical
00071         float       scaleX;
00072         float       scaleY;
00073         float       scaleW;
00074         float       scaleH;
00075     };
00076 
00077     static const int  RECTANGLE = 1;
00078     static const int  OVAL      = 2;
00079 
00080     Graph(Window* parent, int w, int h, int drawShape=0, strconst txt="") :
00081         SizableWindow(parent, w, h)
00082     {
00083         Init(drawShape, txt);
00084     }
00085 
00086     Graph(Window* parent, int x, int y, int w, int h, int drawShape=0,
00087           strconst txt=""):
00088         SizableWindow(parent, x, y, w, h)
00089     {
00090         Init(drawShape, txt);
00091     }
00092 
00093     int NrOfNodes()
00094     {
00095         return mNodes.size();
00096     }
00097 
00098     int FindNodeIdx(Node* node)
00099     {
00100         for (int i=0; i<mNodes.size(); i++)
00101         {
00102             if (mNodes[i].nodeVector[0] == node)
00103                 return i;
00104         }
00105         return -1;
00106     }
00107 
00108     Node* GetNode(int idx)
00109     {
00110         if (idx<0 || idx>mNodes.size()-1)
00111             return 0;
00112         return mNodes[idx].nodeVector[0];
00113     }
00114 
00115     int AddNode(Node* node, int scaleOption=0, Graph* graph=0)
00116     {
00117         NodeInfo nodeInfo;
00118 
00119         nodeInfo.graphPtr   = graph;
00120         nodeInfo.scaleMode  = scaleOption; // 0, NoHorizontal and/or NoVertical
00121 
00122         nodeInfo.nodeVector.push_back(node);
00123         mNodes.push_back(nodeInfo);
00124         return mNodes.size()-1;
00125     }
00126 
00127     int AddNode(Graph* graphWnd, int scaleOption=0)
00128     {
00129         return AddNode((Node*)graphWnd, scaleOption, graphWnd);
00130     }
00131 
00132     void RemoveNodeIdx(int idx)
00133     {
00134         if (idx < 0 || idx >= mNodes.size())
00135             return;
00136         Node* node = mNodes[idx].nodeVector[0];
00137         for (int i=0; i<mNodes.size(); i++)
00138         {
00139             NodeVector& nodeVector = mNodes[i].nodeVector;
00140             for (int j=nodeVector.size()-1; j>=0; j--)
00141                 if (nodeVector[j] == node)
00142                     nodeVector.erase(nodeVector.begin()+j);
00143         }
00144         mNodes.erase(mNodes.begin()+idx);
00145         // RvB: Maybe change interface so that we do not simply add nodes
00146         // but we add OglGui::window or OglGui::View derived objects.
00147         // Than destruction is possible and safe.
00148         // delete (OglGui::Window*) node;
00149     }
00150 
00151     void RemoveNode(Node* node)
00152     {
00153         RemoveNodeIdx(FindNodeIdx(node));
00154     }
00155 
00156     void ClearNodes()
00157     {
00158         mNodes.clear();
00159     }
00160 
00161     void ConnectNode(Node* fromNode, Node* toNode, ULONG startCol=oglBLACK,
00162                      ULONG endCol=oglBLACK)
00163     {
00164         int idx = FindNodeIdx(fromNode);
00165         if (idx==-1)
00166             return;
00167         NodeInfo& nodeInfo = mNodes[idx];
00168         nodeInfo.nodeVector.push_back(toNode);
00169         nodeInfo.lineStartColors.push_back(startCol);
00170         nodeInfo.lineEndColors.push_back(endCol);
00171     }
00172 
00173     virtual void AlignString(int offsetX=0, int offsetY=0)
00174     {
00175         if (mText.empty())
00176             return;
00177         int     x, y;
00178         ULONG   fCol = GetState() ? GetForeground() : oglGREY;
00179 
00180         oglSys.AlignTextXY(mOglWnd, (char *) mText.c_str(), mAlignH, mAlignV,
00181                            mOglWnd->width, mOglWnd->height, &x, &y);
00182         y += 3 + offsetY;
00183         x += offsetX;
00184         glNormal3f(0,0,1);
00185         if (mTextShadowed)
00186             oglSys.ShadowPrintf(mOglWnd, x, y, mShadowColor, fCol,
00187                                 "%s", mText.c_str());
00188         else
00189             oglSys.PosColPrintf(mOglWnd, x, y, fCol, "%s", mText.c_str());
00190     }
00191 
00192     void DrawShape()
00193     {
00194         if (!mDrawShape)
00195             return;
00196 
00197         int w = W(), h = H();
00198         if (mShapeBg)
00199         {
00200             int bInfo[3];
00201             if (mShapeBg & 0xff000000)
00202                 oglSys.StartBlend(bInfo);
00203             SetSolidFillColor(mShapeBg);
00204             if (mDrawShape == OVAL)
00205                 FillOval(w/2,h/2,w/2,h/2);
00206             else
00207                 FillRectangle(0,0,w-1,h-1);
00208              if (mShapeBg & 0xff000000)
00209                 oglSys.EndBlend(bInfo);
00210         }
00211         if (mShapeFg & 0xff000000)
00212         {
00213             SetSolidLineColor(mShapeFg);
00214             if (mDrawShape == OVAL)
00215                 DrawOval(w/2,h/2,w/2,h/2);
00216             else
00217                 DrawRectangle(0.5,0.5,w-1,h-1);
00218         }
00219     }
00220 
00221     void DrawConnections()
00222     {
00223         glLineWidth(2);
00224         for (int i=0; i < mNodes.size(); i++)
00225         {
00226             int     x, y, w, h;
00227             Node*   node = mNodes[i].nodeVector[0];
00228             node->GetDimensions(x,y,w,h);
00229 
00230             int     srcX = x + w/2;
00231             int     srcY = y + h/2;
00232 
00233             NodeVector&     nodeVector      = mNodes[i].nodeVector;
00234             ColorVector&    colStartVector  = mNodes[i].lineStartColors;
00235             ColorVector&    colEndVector    = mNodes[i].lineEndColors;
00236             for (int j=1; j < nodeVector.size(); j++)
00237             {
00238                 Node* dstNode = nodeVector[j];
00239                 dstNode->GetDimensions(x,y,w,h);
00240 
00241                 int dstX = x + w/2;
00242                 int dstY = y + h/2;
00243                 SetLineColors(colStartVector[j-1],colEndVector[j-1],0,0);
00244                 DrawLine(srcX, srcY, dstX, dstY);
00245             }
00246         }
00247         glLineWidth(1);
00248     }
00249 
00250     void SetShowContentAt(int minW, int minH)
00251     {
00252         mShowContentMinW = minW;
00253         mShowContentMinH = minH;
00254     }
00255 
00256     void HandleShowContent()
00257     {
00258         bool showContent = W() >= mShowContentMinW && H() >= mShowContentMinH;
00259         if (!showContent && (mOglWnd->wndList || mOglWnd->objectList))
00260         {
00261             mOldWndList      = mOglWnd->wndList;
00262             mOldObjectList   = mOglWnd->objectList;
00263             mOglWnd->wndList = mOglWnd->objectList = 0;
00264         }
00265         if (showContent && !(mOglWnd->wndList || mOglWnd->objectList))
00266         {
00267             mOglWnd->wndList    = mOldWndList;
00268             mOglWnd->objectList = mOldObjectList;
00269         }
00270         if (showContent)
00271             DrawConnections();
00272     }
00273 
00274     virtual void DisplayFunc()
00275     {
00276         OGC myOGC;
00277         OGCSave(&myOGC);
00278         HandleShowContent();
00279         DrawShape();
00280         AlignString(mAlignOffH, mAlignOffV);
00281         SizableWindow::DisplayFunc();
00282         if (mDocBased && mDocLines)
00283         {
00284             SetSolidLineColor(oglBLACK);
00285             DrawRectangle(mDocX,mDocY,mDocW, mDocH);
00286         }
00287         OGCRestore(&myOGC);
00288     }
00289 
00290     void StartScalers()
00291     {
00292         if (mDocBased)
00293         {
00294             mDocScaleX = mDocX/(float)W();
00295             mDocScaleY = mDocY/(float)H();
00296             mDocScaleW = mDocW/(float)W();
00297             mDocScaleH = mDocH/(float)H();
00298         }
00299         int wndW = mDocBased ? DocW() : W();
00300         int wndH = mDocBased ? DocH() : H();
00301         for (int i=0; i < mNodes.size(); i++)
00302         {
00303             NodeInfo& nodeInfo = mNodes[i];
00304             int x, y, w, h;
00305             nodeInfo.nodeVector[0]->GetDimensions(x, y, w, h);
00306             x = mDocBased ? -mDocX + x : x;
00307             y = mDocBased ? -mDocY + y : y;
00308             nodeInfo.scaleX = x/(float)wndW;
00309             nodeInfo.scaleY = y/(float)wndH;
00310             nodeInfo.scaleW = w/(float)wndW;
00311             nodeInfo.scaleH = h/(float)wndH;
00312             if (nodeInfo.graphPtr)
00313                 nodeInfo.graphPtr->StartScalers();
00314         }
00315     }
00316 
00317     void DoScaling(bool passive=false)
00318     {
00319         if (passive && mDocBased)
00320         {
00321             mDocX = mDocScaleX * W();
00322             mDocY = mDocScaleY * H();
00323             mDocW = mDocScaleW * W();
00324             mDocH = mDocScaleH * H();
00325         }
00326         int lw = mDocBased ? DocW() : W();
00327         int lh = mDocBased ? DocH() : H();
00328         for (int i=0; i < mNodes.size(); i++)
00329         {
00330             NodeInfo&   nodeInfo = mNodes[i];
00331             Node*       node     = nodeInfo.nodeVector[0];
00332             int         mode     = nodeInfo.scaleMode;
00333 
00334             int         fx, fy, fw, fh;
00335             node->GetDimensions(fx,fy,fw,fh);
00336             if(!(mode & NoHorizontal))
00337             {
00338                 fx = (int)(lw * nodeInfo.scaleX);
00339                 if(!(mode & NoWidth))
00340                     fw = (int)(lw * nodeInfo.scaleW);
00341             }
00342             if(!(mode & NoVertical))
00343             {
00344                 fy = (int)(lh * nodeInfo.scaleY);
00345                 if(!(mode & NoHeight))
00346                     fh = (int)(lh * nodeInfo.scaleH);
00347             }
00348 
00349             node->SetDimensions(fx+mDocX, fy+mDocY, fw, fh);
00350             if (nodeInfo.graphPtr)
00351                 nodeInfo.graphPtr->DoScaling(true);
00352         }
00353     }
00354 
00355     void DoPanning()
00356     {
00357         int sz = mNodes.size();
00358         for (int i=0; i < mNodes.size(); i++)
00359         {
00360             NodeInfo&   nodeInfo = mNodes[i];
00361             Node*       node     = nodeInfo.nodeVector[0];
00362 
00363             int fx, fy, fw, fh;
00364             node->GetDimensions(fx,fy,fw,fh);
00365             node->SetDimensions(fx-mPanDifX,fy-mPanDifY,fw,fh);
00366         }
00367     }
00368 
00369     virtual void DocX(int x)
00370     {
00371         mPanDifY = 0;
00372         if (mPanDifX = mDocX-x)
00373         {
00374             mDocX = x;
00375             DoPanning();
00376         }
00377     }
00378 
00379     virtual void DocY(int y)
00380     {
00381         mPanDifX = 0;
00382         if (mPanDifY = mDocY-y)
00383         {
00384             mDocY = y;
00385             DoPanning();
00386         }
00387     }
00388 
00389     // MouseFunc used when Graph contents is window based.
00390     virtual void WndMouseFunc(int msg, int btn, int state, int x, int y)
00391     {
00392         bool zoomState = (state==(oglLeftButton|oglControl|oglShift));
00393         if (!zoomState)
00394             mZooming = false;
00395         if (!mZooming && !zoomState)
00396             SizableWindow::MouseFunc(msg, btn, state, x, y);
00397         if (msg == oglMouseDown && btn == oglLeftButton && zoomState)
00398         {
00399             mZooming    = mZoomable ? true : false;
00400             mStartTopX  = x;
00401             mStartTopY  = y;
00402             oglSys.VPToTopWndI(mOglWnd, &mStartTopX, &mStartTopY);
00403             mLastX = mStartTopX;
00404             mNormX = x / (float) W();
00405             mNormY = y / (float) H();
00406             if (mZooming)
00407                 StartScalers();
00408         }
00409         if (msg == oglMouseMove && mZooming)
00410         {
00411             int topX = x, topY = y;
00412             oglSys.VPToTopWndI(mOglWnd,&topX, &topY);
00413             int difX = mLastX-topX;
00414             int nX, nY, nW, nH;
00415             GetDimensions(nX,nY,nW,nH);
00416             int nnW = (1.0-(difX/100.0)) * nW;
00417             if (nnW==nW && difX) // If rounding stops size difference
00418                 nnW -= difX;
00419             if (nnW >= mMinW && nnW <= mMaxW)
00420                 nW = nnW;
00421             int nnH = (1.0-(difX/100.0)) * nH;
00422             if (nnH==nH && difX) // If rounding stops size difference
00423                 nnH -= difX;
00424             if (nnH >= mMinH && nnH <= mMaxH)
00425                 nH = nnH;
00426             nX = mStartTopX - mNormX * nW;
00427             nY = mStartTopY - mNormY * nH;
00428             oglSys.TopWndToVPI(GetParent()->GetOGLWND(), &nX, &nY);
00429             ClampMinMax(nX, nY, nW, nH);
00430             SetDimensions(nX, nY, nW, nH);
00431             DoScaling();
00432             mLastX = topX;
00433         }
00434     }
00435 
00436     // MouseFunc used when Graph contents is DocDimensions based.
00437     virtual void DocMouseFunc(int msg, int btn, int state, int x, int y)
00438     {
00439         bool zoomState = (state==(oglLeftButton|oglControl|oglShift));
00440         bool panState  = (state==(oglLeftButton|oglShift));
00441         if (!zoomState)
00442             mZooming = false;
00443         if (!panState)
00444             mPanning = false;
00445         if (msg == oglMouseDown && btn == oglLeftButton)
00446         {
00447             mZooming = mZoomable  ? zoomState : false;
00448             mPanning = mAllowMove ? panState  : false;
00449             mStartTopX = mLastX = x;
00450             mStartTopY = mLastY = y;
00451             mNormX = (mStartTopX-mDocX) / (float) DocW();
00452             mNormY = (mStartTopY-mDocY) / (float) DocH();
00453             if (mZooming)
00454                 StartScalers();
00455         }
00456         if (!mZooming && !mPanning)
00457             Window::MouseFunc(msg,btn,state,x,y);
00458         if (msg == oglMouseMove && (mZooming||mPanning))
00459         {
00460             int nX, nY, nW, nH;
00461             GetDocDimensions(nX,nY,nW,nH);
00462             if (mZooming)
00463             {
00464                 int difX = mLastX-x;
00465                 if ((nW *= (1.0-(difX/100.0)))<12)
00466                     nW = 12;
00467                 if ((nH *= (1.0-(difX/100.0)))<12)
00468                     nH = 12;
00469                 nX = mStartTopX - mNormX * nW;
00470                 nY = mStartTopY - mNormY * nH;
00471             }
00472             if (mPanning)
00473             {
00474                 mPanDifX = mLastX - x;
00475                 mPanDifY = mLastY - y;
00476                 nX -= mPanDifX;
00477                 nY -= mPanDifY;
00478             }
00479             mLastX = x;
00480             mLastY = y;
00481 
00482             bool sizeChange = (nW != mDocW || nH != mDocH);
00483             bool posChange  = (nX != mDocX || nY != mDocY);
00484             if (posChange || sizeChange)
00485                 SetDocDimensions(nX, nY, nW, nH);
00486             if (mZooming && sizeChange)
00487                 DoScaling();
00488             if (mPanning && posChange)
00489                 DoPanning();
00490         }
00491     }
00492 
00493     virtual void MouseFunc(int msg, int btn, int state, int x, int y)
00494     {
00495         if (mDocBased)
00496             DocMouseFunc(msg,btn,state,x,y);
00497         else
00498             WndMouseFunc(msg,btn,state,x,y);
00499     }
00500 
00502 // Setters/Getters
00503     void        Shape(int shape)                { mDrawShape = shape; }
00504     ULONG       Shape()                         { return mDrawShape; }
00505     void        ShapeBg(ULONG col)              { mShapeBg = col; }
00506     ULONG       ShapeBg()                       { return mShapeBg; }
00507     void        ShapeFg(ULONG col)              { mShapeFg = col; }
00508     ULONG       ShapeFg()                       { return mShapeFg; }
00509     void        SetText(std::string text)       { mText = text; }
00510     std::string GetText() const                 { return mText; }
00511     void        SetTextShadowed(bool mode=true) { mTextShadowed = mode; }
00512     void        SetShadowColor(ULONG shadCol)   { mShadowColor = shadCol; }
00513     ULONG       GetShadowColor() const          { return mShadowColor; }
00514     void        Zoomable(bool mode)             { mZoomable = mode; }
00515     bool        Zoomable()                      { return mZoomable; }
00516     void        Panable(bool mode)              { mAllowMove = mode; }
00517     bool        Panable()                       { return mAllowMove; }
00518     void        DocLines(bool mode)             { mDocLines = mode; }
00519     bool        DocLines()                      { return mDocLines; }
00520     void        DocBased(bool mode)             { mDocBased = mode; }
00521     bool        DocBased()                      { return mDocBased; }
00522     int         NrNodes()                       { return mNodes.size(); }
00523 
00524     void GetAlign(int& hAlign, int& vAlign) const
00525     {
00526         hAlign = mAlignH;
00527         vAlign = mAlignV;
00528     }
00529 
00530     void SetAlign(int hAlign, int vAlign=oglCenterAlign)
00531     {
00532         mAlignH = hAlign;
00533         mAlignV = vAlign;
00534     }
00535 
00536     void SetAlignOffsets(int hOff, int vOff)
00537     {
00538         mAlignOffH = hOff;
00539         mAlignOffV = vOff;
00540     }
00541 
00542     void SetCentered(bool val)
00543     {
00544         mAlignH = val ? oglCenterAlign : oglLeftAlign;
00545         mAlignV = oglCenterAlign;
00546     }
00547 
00548 protected:
00549     std::vector<NodeInfo>   mNodes;
00550     std::string             mText;
00551     int                     mAlignH, mAlignOffH;
00552     int                     mAlignV, mAlignOffV;
00553     int                     mDrawShape;
00554 
00555     ULONG                   mShapeBg;
00556     ULONG                   mShapeFg;
00557     ULONG                   mShadowColor;
00558 
00559     float                   mDocScaleX;
00560     float                   mDocScaleY;
00561     float                   mDocScaleW;
00562     float                   mDocScaleH;
00563 
00564     bool                    mTextShadowed;
00565     bool                    mDocBased;
00566     bool                    mDocLines;
00567     bool                    mZoomable;
00568     bool                    mZooming;
00569     bool                    mPanning;
00570 
00571 
00572 private:
00573     void Init(int drawShape, strconst txt)
00574     {
00575         mText           = txt;
00576         mTextShadowed   = false;
00577         mShadowColor    = oglLIGHTGREY;
00578         mAlignH         = oglCenterAlign;
00579         mAlignV         = oglCenterAlign;
00580         mAlignOffH      = 0;
00581         mAlignOffV      = 0;
00582 
00583         mDrawShape      = drawShape;
00584         mShapeBg        = 0xe0ff8080;
00585         mShapeFg        = mForeGroundColor;
00586 
00587         mZoomable       = true;
00588         mZooming        = false;
00589         mPanning        = false;
00590         mDocBased       = false;
00591         mDocLines       = true;
00592 
00593         mDocX           = 0;
00594         mDocY           = 0;
00595         mDocW           = W();
00596         mDocH           = H();
00597 
00598         mShowContentMinW    = 40;
00599         mShowContentMinH    = 40;
00600         mOldWndList         = 0;
00601         mOldObjectList      = 0;
00602 
00603         ActOnModifier(oglShift);
00604     }
00605 
00606     int                 mShowContentMinW;
00607     int                 mShowContentMinH;
00608     int                 mLastX;
00609     int                 mLastY;
00610     int                 mStartTopX;
00611     int                 mStartTopY;
00612     int                 mPanDifX;
00613     int                 mPanDifY;
00614     float               mNormX;
00615     float               mNormY;
00616 
00617     LIST*               mOldWndList;
00618     LIST*               mOldObjectList;
00619 };
00620 
00621 } // Namespace OglGui
00622 #endif
00623 

Generated on Fri Mar 19 09:31:35 2010 for ImpalaSrc by  doxygen 1.5.1