home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / src / mactech / volume18_2002 / 18.05.sit / 18.05 / PC / CGraphWindow.cp < prev    next >
Text File  |  2002-01-30  |  11KB  |  419 lines

  1. //////////////////////////////////////////////////////////////////////
  2. //
  3. // Graph Window
  4. // Written by Allen Stenger, January 2002
  5. //
  6. // This draws the graph in a window.
  7. //
  8. // This reads in the graph descriptions from file and creates a 
  9. // document window with a drawing of the graph inside. It also takes
  10. // care of scrolling and redrawing the document window.
  11. //
  12. //////////////////////////////////////////////////////////////////////
  13.  
  14. #include "CGraphWindow.h"
  15. #include "SxChartApp.h"
  16.  
  17. #include <fstream>
  18. #include <sstream>
  19.  
  20. static const Rect kPicClipRect = {0, 0, 32767, 32767};    
  21.                         // Picture's clipping rect
  22.  
  23. static const int kMaxZoom = 1 << 8;    // 2^(max number of zoom outs)
  24.  
  25. //////////////////////////////////////////////////////////////////////
  26. // CGraphWindow implementation
  27. //////////////////////////////////////////////////////////////////////
  28.  
  29. // class static variables
  30. std::vector<CGraphWindow *> CGraphWindow::fgGraphWindows;
  31.  
  32. CGraphWindow::CGraphWindow(LStream *pStream) :
  33. LWindow(pStream),
  34. fpGraphView(0)
  35. {
  36.     // add ourselves to list
  37.     fgGraphWindows.push_back(this);
  38.     
  39.     // add a placeholder title to the Window menu
  40.     // (we don't know our title yet)
  41.     LMenu *pWindowMenu = 
  42.         LMenuBar::GetCurrentMenuBar()->FetchMenu(kWindowMENU);
  43.     pWindowMenu->InsertCommand( "\p ", cmd_UseMenuItem, 16000 );
  44.     LCommander::SetUpdateCommandStatus(true);
  45. }
  46.  
  47. CGraphWindow::~CGraphWindow()
  48. {
  49.     // remove ourselves from Window menu
  50.     LMenu *pWindowMenu = 
  51.         LMenuBar::GetCurrentMenuBar()->FetchMenu(kWindowMENU);
  52.     std::vector<CGraphWindow *>::iterator iter =
  53.         std::lower_bound(fgGraphWindows.begin(), 
  54.                         fgGraphWindows.end(), this);
  55.     int itemNumber = iter - fgGraphWindows.begin() + 1;
  56.     pWindowMenu->RemoveItem(itemNumber);
  57.     LCommander::SetUpdateCommandStatus(true);
  58.     
  59.     // remove ourselves from list -
  60.     // use erase-remove idiom (see Meyers, "Effective STL" item 32)
  61.     fgGraphWindows.erase(
  62.         std::remove(fgGraphWindows.begin(), fgGraphWindows.end(), this),
  63.         fgGraphWindows.end());
  64. }
  65.  
  66. void CGraphWindow::FindCommandStatus(
  67.                                 CommandT            inCommand,
  68.                                 Boolean&            outEnabled,
  69.                                 Boolean&            outUsesMark,
  70.                                 UInt16&                outMark,
  71.                                 Str255                outName)
  72. {
  73.     ResIDT    theMenuID;
  74.     SInt16    theMenuItem;
  75.     if (IsSyntheticCommand(inCommand, theMenuID, theMenuItem) &&
  76.         theMenuID == kWindowMENU && theMenuItem > 0)
  77.     {
  78.         // window items are always enabled;
  79.         // place checkmark next to frontmost window;
  80.         // supply the window title because we didn't know
  81.         // it at window creation time
  82.         LWindow    *pWindow = fgGraphWindows[theMenuItem -1];
  83.         pWindow->GetDescriptor(outName);
  84.         outEnabled = true;
  85.         outUsesMark = true;
  86.         outMark = noMark;
  87.  
  88.         if (pWindow == UDesktop::FetchTopRegular())            
  89.             outMark = checkMark;
  90.     }
  91.     else
  92.     {
  93.         switch (inCommand)
  94.         {
  95.             case cmd_ZoomOut:
  96.             {
  97.                 int zoom1 = fpGraphView->GetZoomFactor();
  98.                 if (zoom1 < kMaxZoom)
  99.                     outEnabled = true;
  100.             }
  101.             break;
  102.             
  103.             case cmd_ZoomIn:
  104.             {
  105.                 int zoom2 = fpGraphView->GetZoomFactor();
  106.                 if (zoom2 > 1)
  107.                     outEnabled = true;
  108.             }
  109.             break;
  110.             
  111.             default: 
  112.             {
  113.                 LWindow::FindCommandStatus(inCommand, outEnabled,
  114.                                         outUsesMark, outMark, outName);
  115.             }
  116.             break;
  117.         }
  118.     }
  119. }
  120.  
  121. Boolean CGraphWindow::ObeyCommand(
  122.                                 CommandT            inCommand,
  123.                                 void*                ioParam)
  124. {
  125.     ResIDT    theMenuID;
  126.     SInt16    theMenuItem;
  127.     Boolean cmdHandled = true;
  128.     if (IsSyntheticCommand(inCommand, theMenuID, theMenuItem) &&
  129.         theMenuID == kWindowMENU && theMenuItem > 0)
  130.     {
  131.         // bring desired window to front
  132.         CGraphWindow *pWindow = fgGraphWindows[theMenuItem - 1];
  133.         UDesktop::SelectDeskWindow(pWindow);
  134.     }
  135.     else
  136.     {
  137.         switch (inCommand)
  138.         {
  139.             case cmd_ZoomOut:
  140.             {
  141.                 int zoom1 = fpGraphView->GetZoomFactor();
  142.                 fpGraphView->SetZoomFactor(2 * zoom1);
  143.             }
  144.             break;
  145.  
  146.             case cmd_ZoomIn:
  147.             {
  148.                 int zoom2 = fpGraphView->GetZoomFactor();
  149.                 fpGraphView->SetZoomFactor(zoom2 / 2);
  150.             }
  151.             break;
  152.             
  153.             default: 
  154.             {
  155.                 cmdHandled = LWindow::ObeyCommand(inCommand, ioParam);
  156.             }
  157.             break;
  158.         }
  159.     }
  160.     
  161.     return cmdHandled;
  162. }
  163.  
  164. void CGraphWindow::FinishCreateSelf()
  165. {
  166.     fpGraphView = static_cast<CGraphView *>(FindPaneByID(kGraphView));
  167.     
  168.     // add attachment to handling page up/down etc. keys
  169.     AddAttachment(new LKeyScrollAttachment(fpGraphView));
  170.     
  171.     LWindow::FinishCreateSelf();
  172. }
  173.  
  174. //////////////////////////////////////////////////////////////////////
  175. // CGraphWindow implementation
  176. //////////////////////////////////////////////////////////////////////
  177.  
  178. CGraphView::CGraphView(LStream *pStream) :
  179. LView(pStream),
  180. fhPicture(0),
  181. fZoomFactor(1)
  182. {
  183.     fPicFrame.top = fPicFrame.left = 0;
  184.     fPicFrame.bottom = fPicFrame.right = 0;
  185. }
  186.  
  187. CGraphView::~CGraphView()
  188. {
  189.     if (fhPicture)
  190.         ::DisposeHandle(reinterpret_cast<Handle>(fhPicture));
  191.     fhPicture = 0;
  192. }
  193.     
  194. void CGraphView::LoadGraph(int testNumber)
  195. {
  196.     fFileNumberString = SxChartApp::TestNumberToString(testNumber);
  197.     
  198.     // How we will handle the unknown picture size:
  199.     // we don't know yet the actual extent of the graph, so
  200.     // we'll use a big source and clipping rectangle, but
  201.     // we'll also keep track of the actual size needed.
  202.     // Then we'll set the view's image size to the actual size.
  203.     // However we will draw into the large sized area to avoid 
  204.     // scaling the picture.
  205.     // We assume the graph will alway start somewhere near (0,0),
  206.     // so that will be our view's initial top left display,
  207.     // even if there's no data around there.
  208.     
  209.     OpenCPicParams myOpenCPicParams;
  210.     myOpenCPicParams.srcRect = kPicClipRect;
  211.     myOpenCPicParams.hRes = 0x00480000;
  212.     myOpenCPicParams.vRes = 0x00480000;
  213.     myOpenCPicParams.version = 2;
  214.     myOpenCPicParams.reserved1 = 0;
  215.     myOpenCPicParams.reserved2 = 0;
  216.     fhPicture = ::OpenCPicture(&myOpenCPicParams);
  217.     
  218.     // set up Picture the way we want it
  219.     ::ClipRect(&kPicClipRect);
  220.     ::PenNormal();
  221.     TextFont(1);    // application font
  222.     TextFace(0);    // plain
  223.     TextMode(srcCopy);    // plain
  224.     TextSize(9);    // 9 point
  225.     
  226.     DrawEdges();
  227.     DrawNames();
  228.     
  229.     ::ClosePicture();
  230.     
  231.     // make image the size of the useful parts of the picture
  232.     ResizeImageTo(
  233.         (fPicFrame.right - fPicFrame.left) / fZoomFactor,
  234.         (fPicFrame.bottom - fPicFrame.top) / fZoomFactor,
  235.         false);
  236.  
  237.     // force redraw now that we have something to draw
  238.     Refresh();
  239. }
  240.     
  241. void CGraphView::DrawSelf()
  242. {
  243.     // code swiped from LPicture::DrawSelf; we don't use
  244.     // LPicture because it requires the picture to be in a resource
  245.     if (fhPicture != nil) 
  246.     {
  247.         Rect destRect = kPicClipRect;
  248.         destRect.top /= fZoomFactor;
  249.         destRect.left /= fZoomFactor;
  250.         destRect.right /= fZoomFactor;
  251.         destRect.bottom /= fZoomFactor;
  252.         ::DrawPicture(fhPicture, &destRect);
  253.     } 
  254.     else 
  255.     {
  256.         Rect    frame;
  257.         CalcLocalFrameRect(frame);
  258.         ::PenNormal();
  259.  
  260.         Pattern        ltGrayPat;
  261.         ::MacFillRect(&frame, UQDGlobals::GetLightGrayPat(<GrayPat));
  262.  
  263.         ::MacFrameRect(&frame);
  264.     }
  265. }
  266.  
  267. void CGraphView::SetZoomFactor(int factor)
  268. {
  269.     // attempt to scroll to the same center after zooming
  270.     SDimension16 frameSize;
  271.     GetFrameSize(frameSize);
  272.     SPoint32    imageLocation;
  273.     GetImageLocation(imageLocation);
  274.     SPoint32 viewCenter;
  275.     viewCenter.h = -imageLocation.h + (frameSize.width / 2);
  276.     viewCenter.v = -imageLocation.v + (frameSize.height / 2);
  277.     viewCenter.h *= fZoomFactor;
  278.     viewCenter.v *= fZoomFactor;
  279.  
  280.     // now do the zoom
  281.     fZoomFactor = factor;
  282.     ResizeImageTo(
  283.         (fPicFrame.right - fPicFrame.left) / fZoomFactor,
  284.         (fPicFrame.bottom - fPicFrame.top) / fZoomFactor,
  285.         false);
  286.  
  287.     // try to re-center
  288.     viewCenter.h /= fZoomFactor;
  289.     viewCenter.v /= fZoomFactor;
  290.     imageLocation.h = (frameSize.width / 2) - viewCenter.h;
  291.     imageLocation.v = (frameSize.height / 2) - viewCenter.v;
  292.     ScrollPinnedImageTo(-imageLocation.h, -imageLocation.v, false);
  293.     Refresh();    // redraw ourself
  294. }
  295.  
  296. int CGraphView::GetZoomFactor()
  297. {
  298.     return fZoomFactor;
  299. }
  300.  
  301. void CGraphView::DrawEdges()
  302. {
  303.     // open correct segments file
  304.     std::ostringstream fileNameStream;
  305.     fileNameStream << "segments" << fFileNumberString << ".out";
  306.     std::string fileName(fileNameStream.str());
  307.     std::ifstream segmentsStream(fileName.c_str());
  308.     if (!segmentsStream.is_open())
  309.     {
  310.         SxChartApp::SayFileError(fileName);
  311.         return;        // give up
  312.     }
  313.     
  314.     // file format is: several blocks of form
  315.     //     number of points
  316.     //     point1horiz,point1vert
  317.     //     ...
  318.     
  319.     // read all blocks
  320.     while (!segmentsStream.eof())
  321.     {
  322.         // read number of points in block
  323.         std::string numPtsString;
  324.         std::getline(segmentsStream, numPtsString);
  325.         int numPts = std::atoi(numPtsString.c_str());
  326.         
  327.         // read all points in block
  328.         for (int i = 0; i < numPts; i++)
  329.         {
  330.             std::string pointLine;
  331.             std::getline(segmentsStream, pointLine);
  332.             std::string::size_type firstComma = pointLine.find(',');
  333.             std::string horizString = pointLine.substr(0, firstComma);
  334.             std::string vertString = pointLine.substr(firstComma + 1);
  335.             Point aVertex;
  336.             aVertex.h = std::atoi(horizString.c_str());
  337.             aVertex.v = std::atoi(vertString.c_str());
  338.             
  339.             // draw segment
  340.             if (i == 0)
  341.                 ::MoveTo(aVertex.h, aVertex.v);
  342.             else
  343.                 ::LineTo(aVertex.h, aVertex.v);
  344.         }
  345.     }
  346.     
  347.  
  348. }
  349.  
  350. void CGraphView::DrawNames()
  351. {
  352.     // we also keep a running set of bounds for the vertices
  353.     int maxH = 0;
  354.     int maxV = 0;
  355.  
  356.     // open correct locations file
  357.     std::ostringstream fileNameStream;
  358.     fileNameStream << "locations" << fFileNumberString << ".out";
  359.     std::string fileName(fileNameStream.str());
  360.     std::ifstream locationsStream(fileName.c_str());
  361.     if (!locationsStream.is_open())
  362.     {
  363.         SxChartApp::SayFileError(fileName);
  364.         return;        // give up
  365.     }
  366.     
  367.     // file format is: several blocks of form
  368.     //     pointhoriz,pointvert,personname
  369.     
  370.     // read all lines
  371.     while (!locationsStream.eof())
  372.     {
  373.         std::string pointLine;
  374.         std::getline(locationsStream, pointLine);
  375.         std::string::size_type firstComma = pointLine.find(',');
  376.         std::string::size_type secondComma = 
  377.                             pointLine.find(',', firstComma + 1);
  378.         std::string horizString = pointLine.substr(0, firstComma);
  379.         std::string vertString = 
  380.             pointLine.substr(firstComma + 1, secondComma - firstComma - 1);
  381.         std::string personName = pointLine.substr(secondComma + 1);
  382.         Point aVertex;
  383.         aVertex.h = std::atoi(horizString.c_str());
  384.         aVertex.v = std::atoi(vertString.c_str());
  385.         
  386.         // draw name at vertex, attempt to center on the vertex;
  387.         // do not draw left of or above 0.
  388.         const int kCharHalfHeight = 5;    // assuming 9 point type
  389.         const char *pPersonString = personName.c_str();
  390.         size_t nameCharLen = personName.length();
  391.         int nameWidth = ::TextWidth(pPersonString, 0, nameCharLen);    
  392.                                 // width in pixels
  393.         aVertex.h -= (nameWidth / 2);
  394.         aVertex.v += kCharHalfHeight;
  395.         if (aVertex.h < 0)
  396.             aVertex.h = 0;
  397.         if (aVertex.v < 2 * kCharHalfHeight)
  398.             aVertex.v = 2 * kCharHalfHeight;
  399.             
  400.         ::MoveTo(aVertex.h, aVertex.v);
  401.         ::MacDrawText(personName.c_str(), 0, personName.length());
  402.                 
  403.         // update bounds
  404.         if (aVertex.h > maxH)
  405.             maxH = aVertex.h;
  406.         if (aVertex.v > maxV)
  407.             maxV = aVertex.v;
  408.     }
  409.     
  410.     // update bounding rect - we somewhat arbitrarily pad it
  411.     // to avoid having the labels clipped off
  412.     const int kPadding = 100;    // units: pixels
  413.     maxV += kPadding;
  414.     maxH += kPadding;
  415.     Rect tempRect = {0, 0, maxV, maxH};
  416.     fPicFrame = tempRect;
  417. }
  418.  
  419.