00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
00049
00050
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
00063 struct NodeInfo {
00064 NodeVector nodeVector;
00065
00066 ColorVector lineStartColors;
00067 ColorVector lineEndColors;
00068 Graph* graphPtr;
00069 int scaleMode;
00070
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;
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
00146
00147
00148
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
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)
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)
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
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
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 }
00622 #endif
00623