|
|
1.1 ! root 1: // chartwnd.cpp : Defines the class behaviors for the Chart frame window. ! 2: // ! 3: // This is a part of the Microsoft Foundation Classes C++ library. ! 4: // Copyright (C) 1992 Microsoft Corporation ! 5: // All rights reserved. ! 6: // ! 7: // This source code is only intended as a supplement to the ! 8: // Microsoft Foundation Classes Reference and Microsoft ! 9: // QuickHelp documentation provided with the library. ! 10: // See these sources for detailed information regarding the ! 11: // Microsoft Foundation Classes product. ! 12: // ! 13: ! 14: #include "chart.h" ! 15: ! 16: #include <math.h> ! 17: ! 18: #include <commdlg.h> ! 19: ! 20: // hPrintDlg and bUserAbort are used to handle the print abort ! 21: // modeless dialog ! 22: // ! 23: static HWND hPrintDlg; ! 24: BOOL bUserAbort; ! 25: ! 26: // CChartWnd static member variables that define the bounds of ! 27: // CChartWnd's custom anisotropic coordinate system ! 28: // ! 29: CRect CChartWnd::rectPage(0, 1000, 1000, 0); ! 30: CRect CChartWnd::rectData(150, 100, 850, 800); ! 31: ! 32: static short nBlue, nGreen, nRed, nCurrentColor; ! 33: ! 34: ///////////////////////////////////////////////////////////////////////////// ! 35: // CChartWnd ! 36: ! 37: BEGIN_MESSAGE_MAP(CChartWnd, CFrameWnd) ! 38: ON_WM_MOUSEMOVE() ! 39: ON_WM_PAINT() ! 40: ON_WM_CREATE() ! 41: ON_WM_CLOSE() ! 42: ! 43: ON_COMMAND(IDM_NEW, OnNew) ! 44: ON_COMMAND(IDM_OPEN, CmdFileOpen) ! 45: ON_COMMAND(IDM_SAVE, CmdFileSave) ! 46: ON_COMMAND(IDM_SAVEAS, CmdFileSaveAs) ! 47: ON_COMMAND(IDM_CHANGE, OnChange) ! 48: ON_COMMAND(IDM_PRINT, OnPrint) ! 49: ON_COMMAND(IDM_EXIT, OnClose) ! 50: ! 51: ON_COMMAND(IDM_BAR, OnBar) ! 52: ON_COMMAND(IDM_LINE, OnLine) ! 53: ! 54: ON_COMMAND(IDM_ABOUT, OnAbout) ! 55: END_MESSAGE_MAP() ! 56: ! 57: // Constructor: ! 58: // ! 59: CChartWnd::CChartWnd() ! 60: { ! 61: m_bUntitled = TRUE; ! 62: m_szFileName = ""; ! 63: m_bChartSerializedOK = FALSE; ! 64: Create("Chart"); ! 65: } ! 66: ! 67: // Destructor: ! 68: // ! 69: CChartWnd::~CChartWnd() ! 70: { ! 71: if (m_pChartObject != NULL) ! 72: { ! 73: delete m_pChartObject; ! 74: m_pChartObject = NULL; ! 75: } ! 76: } ! 77: ! 78: // Create: ! 79: // Load accelerator keys for this window and create a frame window. ! 80: // The frame window uses a custom window class because it has a ! 81: // non-standard icon. ! 82: // The accelerator table, main menu, and icon are defined in chart.rc. ! 83: // ! 84: BOOL CChartWnd::Create(LPCSTR szTitle, ! 85: LONG style /* = WS_OVERLAPPEDWINDOW */, ! 86: const RECT& rect /* = rectDefault */, ! 87: CWnd* parent /* = NULL */) ! 88: { ! 89: LoadAccelTable("MainAccelTable"); ! 90: ! 91: const char* pszWndClass = ! 92: AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, ! 93: NULL, ! 94: (HBRUSH)(COLOR_WINDOW+1), ! 95: LoadIcon(AfxGetInstanceHandle(), "chart")); ! 96: ! 97: return CFrameWnd::Create(pszWndClass, szTitle, style, ! 98: rect, parent, "MainMenu"); ! 99: } ! 100: ! 101: // OnCreate: ! 102: // Get cursors and initialize the main menu ! 103: // ! 104: int CChartWnd::OnCreate(LPCREATESTRUCT) ! 105: { ! 106: m_pChartObject = NULL; ! 107: m_hCross = LoadCursor(NULL, IDC_CROSS); ! 108: m_hArrow = LoadCursor(NULL, IDC_ARROW); ! 109: ! 110: UpdateMenu(); ! 111: ! 112: return 0; ! 113: } ! 114: ! 115: // UpdateMenu: ! 116: // Update main menu item state based on chart state ! 117: // ! 118: void CChartWnd::UpdateMenu() ! 119: { ! 120: CMenu* menu = GetMenu(); ! 121: ! 122: UINT nData = (m_pChartObject? MF_ENABLED : MF_GRAYED); ! 123: ! 124: menu->EnableMenuItem(IDM_SAVEAS, nData); ! 125: menu->EnableMenuItem(IDM_CHANGE, nData); ! 126: menu->EnableMenuItem(IDM_PRINT, nData); ! 127: ! 128: menu->EnableMenuItem(IDM_BAR, nData); ! 129: menu->EnableMenuItem(IDM_LINE, nData); ! 130: ! 131: if (m_pChartObject != NULL) ! 132: { ! 133: nData = (m_pChartObject->m_nType == IDM_BAR); ! 134: menu->CheckMenuItem(IDM_BAR, nData? MF_CHECKED : MF_UNCHECKED); ! 135: menu->CheckMenuItem(IDM_LINE, nData? MF_UNCHECKED : MF_CHECKED); ! 136: menu->EnableMenuItem(IDM_SAVE, ! 137: m_bUntitled ? MF_GRAYED : MF_ENABLED); ! 138: ! 139: ! 140: } ! 141: else ! 142: { ! 143: menu->CheckMenuItem(IDM_BAR, MF_UNCHECKED); ! 144: menu->CheckMenuItem(IDM_LINE, MF_UNCHECKED); ! 145: menu->EnableMenuItem(IDM_SAVE, MF_GRAYED); ! 146: } ! 147: ! 148: DrawMenuBar(); ! 149: } ! 150: ! 151: // OnNew: ! 152: // Create a new empty chart ! 153: // ! 154: void CChartWnd::OnNew() ! 155: { ! 156: if (m_pChartObject != NULL) ! 157: { ! 158: if (m_pChartObject->m_bDirty) ! 159: { ! 160: ! 161: if (MessageBox("Save existing data?", "Chart", ! 162: MB_YESNO | MB_ICONQUESTION) == IDYES) ! 163: { ! 164: SaveFile(m_bUntitled); ! 165: } ! 166: } ! 167: ! 168: delete m_pChartObject; ! 169: m_pChartObject = NULL; ! 170: m_bUntitled = TRUE; ! 171: m_szFileName = ""; ! 172: m_pChartObject = NULL; ! 173: } ! 174: OnChange(); ! 175: } ! 176: ! 177: // OnChange: ! 178: // User wants to enter (or change) chart data. ! 179: // ! 180: void CChartWnd::OnChange() ! 181: { ! 182: // Create data structure if there is none. ! 183: // ! 184: if (m_pChartObject == NULL) ! 185: { ! 186: m_pChartObject = new CChartObject(); ! 187: } ! 188: ! 189: // Get the data. ! 190: // ! 191: CEntryDialog entryDlg(this); ! 192: entryDlg.DoModal(m_pChartObject); ! 193: ! 194: ASSERT(m_pChartObject->m_pChartData != NULL); ! 195: ! 196: if (m_pChartObject->m_pChartData->IsEmpty()) ! 197: { ! 198: delete m_pChartObject; ! 199: m_pChartObject = NULL; ! 200: } ! 201: ! 202: // Update menu state based on the data ! 203: // ! 204: UpdateMenu(); ! 205: Invalidate(TRUE); ! 206: } ! 207: ! 208: // OnPrint: ! 209: // User wants to print the chart ! 210: // ! 211: void CChartWnd::OnPrint() ! 212: { ! 213: if (!DoPrint()) ! 214: { ! 215: MessageBox("Not able to print chart.", "Chart", ! 216: MB_OK | MB_ICONEXCLAMATION); ! 217: } ! 218: } ! 219: ! 220: // OnBar: ! 221: // Make the chart a bar chart ! 222: // ! 223: void CChartWnd::OnBar() ! 224: { ! 225: ASSERT(m_pChartObject != NULL); ! 226: ! 227: m_pChartObject->m_nType = IDM_BAR; ! 228: ! 229: UpdateMenu(); ! 230: Invalidate(TRUE); ! 231: } ! 232: ! 233: // OnLine: ! 234: // Make the chart a line chart ! 235: // ! 236: void CChartWnd::OnLine() ! 237: { ! 238: ASSERT(m_pChartObject != NULL); ! 239: ! 240: m_pChartObject->m_nType = IDM_LINE; ! 241: ! 242: UpdateMenu(); ! 243: Invalidate(TRUE); ! 244: } ! 245: ! 246: // PrepareDC: ! 247: // Prepare a DC for drawing the chart ! 248: void CChartWnd::PrepareDC(CDC* pDC) ! 249: { ! 250: pDC->SetMapMode(MM_ANISOTROPIC); ! 251: pDC->SetWindowExt(rectPage.right, rectPage.top); ! 252: pDC->SetViewportExt(m_cxClient, -m_cyClient); ! 253: pDC->SetViewportOrg(0, m_cyClient); ! 254: pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); ! 255: pDC->SetBkColor(::GetSysColor(COLOR_WINDOW)); ! 256: } ! 257: ! 258: // OnMouseMove: ! 259: // We do some hit-testing here to make the cursor a crosshairs while inside ! 260: // the data graphic, and an arrow otherwise. ! 261: // ! 262: void CChartWnd::OnMouseMove(UINT, CPoint mousePos) ! 263: { ! 264: if (m_pChartObject == NULL) ! 265: { ! 266: SetCursor(m_hArrow); ! 267: return; ! 268: } ! 269: ! 270: // We use a custom logical coordinate system. 0,0 is the bottom-left ! 271: // corner of the client area, and 1000,1000 is the top-right. ! 272: // Convert the mouse coordinates to this scheme. ! 273: // ! 274: CDC* pDC; ! 275: pDC = GetDC(); ! 276: PrepareDC(pDC); ! 277: pDC->DPtoLP(&mousePos, 1); ! 278: ! 279: if (rectData.PtInRect(mousePos)) ! 280: { ! 281: SetCursor(m_hCross); ! 282: } ! 283: else ! 284: { ! 285: SetCursor(m_hArrow); ! 286: } ! 287: ! 288: ReleaseDC(pDC); ! 289: } ! 290: ! 291: // OnPaint: ! 292: // Paint the chart... ! 293: // ! 294: void CChartWnd::OnPaint() ! 295: { ! 296: CPaintDC dc(this); ! 297: CRect screenPos; ! 298: ! 299: GetClientRect(screenPos); ! 300: ! 301: m_cxClient = screenPos.Width(); ! 302: m_cyClient = screenPos.Height(); ! 303: ! 304: if (m_pChartObject != NULL) ! 305: { ! 306: RenderChart(&dc); ! 307: } ! 308: } ! 309: ! 310: // OnClose: ! 311: // User picked 'Close' on system menu ! 312: // ! 313: void CChartWnd::OnClose() ! 314: { ! 315: if (m_pChartObject != NULL) ! 316: { ! 317: if (m_pChartObject->m_bDirty) ! 318: { ! 319: int fResponse; ! 320: ! 321: fResponse = MessageBox("Save file before exit?", "Chart", ! 322: MB_YESNOCANCEL | MB_ICONQUESTION); ! 323: ! 324: if (fResponse == IDCANCEL) ! 325: { ! 326: return; ! 327: } ! 328: else if (fResponse == IDYES) ! 329: { ! 330: SaveFile(m_bUntitled); ! 331: } ! 332: } ! 333: delete m_pChartObject; ! 334: } ! 335: ! 336: m_pChartObject = NULL; ! 337: ! 338: DestroyWindow(); ! 339: } ! 340: ! 341: // GetHighValue: ! 342: // Returns largest value in chart data. ! 343: // ! 344: short CChartWnd::GetHighValue() ! 345: { ! 346: short i, count, nLargest, nCurrent; ! 347: POSITION pos; ! 348: CChartData* ptr; ! 349: ! 350: ASSERT(m_pChartObject != NULL); ! 351: CObList* pChartData = m_pChartObject->m_pChartData; ! 352: ! 353: ASSERT(pChartData != NULL); ! 354: ! 355: ptr = (CChartData*)(pChartData->GetHead()); ! 356: ! 357: nLargest = ptr->height; ! 358: ! 359: pos = pChartData->GetHeadPosition(); ! 360: count = pChartData->GetCount(); ! 361: for (i = 0; i < count; i++) ! 362: { ! 363: ptr = (CChartData*)pChartData->GetNext(pos); ! 364: ! 365: if ((nCurrent = ptr->height) > nLargest) ! 366: { ! 367: nLargest = nCurrent; ! 368: } ! 369: } ! 370: ! 371: return nLargest; ! 372: } ! 373: ! 374: // SetNewColors: ! 375: // Progresses nCurrentColor through the possible colors. ! 376: // ! 377: void CChartWnd::SetNewColors() ! 378: { ! 379: nCurrentColor++; ! 380: ! 381: ASSERT(m_pChartObject != NULL); ! 382: ASSERT(m_pChartObject->m_pChartData != NULL); ! 383: ! 384: nCurrentColor %= (m_pChartObject->m_pChartData->GetCount()+1); ! 385: ! 386: nBlue = (nCurrentColor & 1) ? 255 : 0; ! 387: nGreen = (nCurrentColor & 2) ? 255 : 0; ! 388: nRed = (nCurrentColor & 4) ? 255 : 0; ! 389: ! 390: } ! 391: ! 392: // RenderChart: ! 393: // Draw the chart in a device context. This routine handles both ! 394: // screen DCs and printer DCs. ! 395: // ! 396: void CChartWnd::RenderChart(CDC* pDC) ! 397: { ! 398: short i, nSize, nTextHeight; ! 399: float yTickMag, yTickGuess; ! 400: char szBuffer[80]; ! 401: ! 402: ASSERT(m_pChartObject != NULL); ! 403: ! 404: if (m_pChartObject->m_pChartData->IsEmpty()) ! 405: { ! 406: return; ! 407: // return if there are no entries in the list ! 408: } ! 409: ! 410: // We use a custom logical coordinate system. 0,0 is the bottom-left ! 411: // corner of the client area, and 1000,1000 is the top-right. ! 412: // ! 413: PrepareDC(pDC); ! 414: ! 415: // A rectangle around the chart. ! 416: // ! 417: pDC->Rectangle(rectData); ! 418: ! 419: // A blue dotted pen to draw the grid on the chart. ! 420: // ! 421: CPen newPen(PS_DOT, 2, RGB(0, 0, 255)); ! 422: CPen* penOrig = pDC->SelectObject(&newPen); ! 423: ! 424: // Figure out a reasonable step size for the grid. ! 425: // ! 426: m_fTallest = GetHighValue(); ! 427: yTickGuess = m_fTallest / 10; ! 428: yTickMag = (float)(((log10(yTickGuess) / log10(2.7182818))) / ! 429: (log10(10.0) / log10(2.7182818))); ! 430: yTickGuess = (float)(((yTickGuess / pow(10, (yTickMag - 1)) + 0.5) / 10) * ! 431: pow(10, yTickMag)); ! 432: ! 433: // Draw grid. ! 434: // ! 435: m_fTallest = yTickGuess * 10; ! 436: int iTickDelta = rectData.Height()/10; ! 437: ! 438: for (i = 1; i <= 10; i++) ! 439: { ! 440: if (i != 10) ! 441: { ! 442: pDC->MoveTo(rectData.left, rectData.top + (iTickDelta*i)); ! 443: pDC->LineTo(rectData.right, rectData.top + (iTickDelta*i)); ! 444: } ! 445: ! 446: sprintf(szBuffer,"%3.2f", (yTickGuess*i)); ! 447: ! 448: nSize = pDC->GetTextExtent(szBuffer,strlen(szBuffer)).cx; ! 449: nTextHeight = pDC->GetTextExtent(szBuffer, strlen(szBuffer)).cy; ! 450: if (((nSize+25) < rectData.left) && (nTextHeight < iTickDelta)) ! 451: { ! 452: pDC->TextOut((125-nSize), ! 453: rectData.top+(iTickDelta*i)+(nTextHeight/2), ! 454: szBuffer, strlen(szBuffer)); ! 455: } ! 456: } ! 457: ! 458: // Done with the grid; re-select the original pen ! 459: ! 460: pDC->SelectObject(penOrig); ! 461: ! 462: // Create and select the brush to draw the chart data itself ! 463: // ! 464: CBrush* pOldBrush; ! 465: CBrush newBrush(RGB(nRed, nGreen, nBlue)); ! 466: pOldBrush = pDC->SelectObject(&newBrush); ! 467: ! 468: switch (m_pChartObject->m_nType) ! 469: { ! 470: case IDM_LINE: ! 471: DrawLineChart(pDC); ! 472: break; ! 473: ! 474: case IDM_BAR: ! 475: DrawBarChart(pDC); ! 476: break; ! 477: } ! 478: ! 479: // Delete the brush, after selecting the old one back in the DC. ! 480: // ! 481: pDC->SelectObject(pOldBrush); ! 482: ! 483: // Draw the title, if there's room. ! 484: // ! 485: nSize = pDC->GetTextExtent(m_pChartObject->m_Title, ! 486: m_pChartObject->m_Title.GetLength()).cx; ! 487: ! 488: if ((nSize/2) < 500) ! 489: { ! 490: pDC->TextOut((500 - (nSize/2)), 900, m_pChartObject->m_Title, ! 491: m_pChartObject->m_Title.GetLength()); ! 492: } ! 493: } ! 494: ! 495: // DrawBarChart: ! 496: // Render the chart as a bar chart ! 497: // ! 498: void CChartWnd::DrawBarChart(CDC* pDC) ! 499: { ! 500: float flFraction; ! 501: short nWidth, i, nTextHeight, nCurrentHeight, nSize; ! 502: CRect rectBar; ! 503: POSITION pos; ! 504: CChartData* ptr; ! 505: char szBuffer[80]; ! 506: ! 507: ASSERT(m_pChartObject != NULL); ! 508: ASSERT(m_pChartObject->m_pChartData != NULL); ! 509: ! 510: CObList* pChartData = m_pChartObject->m_pChartData; ! 511: ! 512: flFraction = (rectData.Width() / (pChartData->GetCount())); ! 513: nWidth = (short) flFraction; ! 514: pos = pChartData->GetHeadPosition(); ! 515: ! 516: nCurrentColor = 0; ! 517: int cChart = pChartData->GetCount(); ! 518: ! 519: for (i = 0; i < cChart; i++) ! 520: { ! 521: char szLabel[40]; ! 522: ptr = (CChartData*)pChartData->GetNext(pos); ! 523: strcpy(szLabel, ptr->szName); ! 524: int nNewHeight = ptr->height; ! 525: ! 526: // Calculate the size of the bar. ! 527: // ! 528: flFraction = nNewHeight / m_fTallest; ! 529: nCurrentHeight = (short) (flFraction * rectData.Height()); ! 530: ! 531: rectBar.left = rectData.left + (nWidth * i); ! 532: rectBar.top = nCurrentHeight + rectData.top; ! 533: rectBar.right = rectData.left + nWidth * (i+1); ! 534: rectBar.bottom = rectBar.top - nCurrentHeight; ! 535: ! 536: SetNewColors(); ! 537: CBrush chartBrush(RGB(nRed, nGreen, nBlue)); ! 538: CBrush* oldBrush = pDC->SelectObject(&chartBrush); ! 539: ! 540: pDC->Rectangle(rectBar); ! 541: ! 542: sprintf(szBuffer, "%s", szLabel); ! 543: nSize = pDC->GetTextExtent(szBuffer,strlen(szBuffer)).cx; ! 544: nTextHeight = pDC->GetTextExtent(szBuffer, strlen(szBuffer)).cy; ! 545: if (((nSize+20) < nWidth) && (nTextHeight < 95)) ! 546: pDC->TextOut(rectBar.left+(nWidth/2)-(nSize/2), ! 547: rectBar.bottom-5, ! 548: szBuffer, strlen(szBuffer)); ! 549: ! 550: // Delete the brush, after selecting the old one back into the DC. ! 551: // ! 552: pDC->SelectObject(oldBrush); ! 553: } ! 554: } ! 555: ! 556: // DrawLineChart: ! 557: // Render the chart data as a line chart ! 558: // ! 559: void CChartWnd::DrawLineChart(CDC* pDC) ! 560: { ! 561: short nWidth, nSize, nTextHeight, i; ! 562: short nCurrentHeight, nBottom; ! 563: ! 564: CPoint ptStart; ! 565: CPoint ptEnd; ! 566: ! 567: LONG nTotalHeight; ! 568: float flFraction, flOffset; ! 569: POSITION pos; ! 570: CChartData* ptr; ! 571: char szBuffer[80]; ! 572: ! 573: ASSERT(m_pChartObject != NULL); ! 574: ! 575: CObList* pChartData = m_pChartObject->m_pChartData; ! 576: ! 577: ASSERT(pChartData != NULL); ! 578: flFraction = (rectData.Width() / (pChartData->GetCount())); ! 579: nWidth = (short) flFraction; ! 580: ! 581: ptr = (CChartData*)pChartData->GetHead(); ! 582: ptStart.x = rectData.left + (nWidth/2); ! 583: nTotalHeight = (LONG)(((LONG)ptr->height) * rectData.Height()); ! 584: flOffset = (nTotalHeight / m_fTallest); ! 585: ptStart.y = rectData.top + (int)flOffset; ! 586: pos = pChartData->GetHeadPosition(); ! 587: ! 588: int cChart = pChartData->GetCount(); ! 589: for (i = 0; i < cChart; i++) ! 590: { ! 591: char szLabel[40]; ! 592: ptr = (CChartData*)pChartData->GetNext(pos); ! 593: strcpy(szLabel, ptr->szName); ! 594: int nNewHeight = ptr->height; ! 595: ! 596: flFraction = nNewHeight / m_fTallest; ! 597: nCurrentHeight = (short) (flFraction * rectData.Height()); ! 598: ! 599: ptEnd.x = nWidth/2 + rectData.left + nWidth*i; ! 600: ptEnd.y = rectData.top + nCurrentHeight; ! 601: nBottom = ptEnd.y - nCurrentHeight; ! 602: ! 603: pDC->MoveTo(ptStart); ! 604: pDC->LineTo(ptEnd); ! 605: ! 606: ptStart = ptEnd; ! 607: ! 608: sprintf(szBuffer, "%s", szLabel); ! 609: nSize = pDC->GetTextExtent(szBuffer, strlen(szBuffer)).cx; ! 610: nTextHeight = pDC->GetTextExtent(szBuffer, strlen(szBuffer)).cy; ! 611: if (((nSize+20) < nWidth) && (nTextHeight < 95)) ! 612: { ! 613: pDC->TextOut((ptEnd.x-(nSize/2)), (nBottom-5), ! 614: szBuffer, strlen(szBuffer)); ! 615: } ! 616: } ! 617: } ! 618: ! 619: // AbortProc: ! 620: // While printing, the Printing... dialog (PrintDlgBox in chart.rc) is ! 621: // displayed, which has a Cancel button on it. This routine replaces the ! 622: // normal message-handling mechanism, until the printing is done or the ! 623: // Cancel button is pressed. ! 624: // ! 625: BOOL FAR PASCAL _export AbortProc(HDC, int) ! 626: { ! 627: MSG msg; ! 628: ! 629: while(!bUserAbort && PeekMessage(&msg,NULL,0,0,PM_REMOVE)) ! 630: { ! 631: if (!hPrintDlg || !IsDialogMessage(hPrintDlg, &msg)) ! 632: { ! 633: TranslateMessage(&msg); ! 634: DispatchMessage(&msg); ! 635: } ! 636: } ! 637: ! 638: return !bUserAbort; ! 639: } ! 640: ! 641: ! 642: // DoPrint: ! 643: // Get a printer DC and render the chart on it. Uses COMMDLG ! 644: // printer dialog. ! 645: // ! 646: BOOL CChartWnd::DoPrint() ! 647: { ! 648: BOOL (FAR PASCAL _export * lpfnAbortProc)(HDC hPrinterDC, int nCode); ! 649: static char szMessage[] = "Printing chart..."; ! 650: short xPage, yPage, oldX, oldY; ! 651: BOOL bError = FALSE; ! 652: CDC* pDC = NULL; ! 653: ! 654: lpfnAbortProc = AbortProc; ! 655: ! 656: CPrintDialog printDialog(FALSE); ! 657: if (printDialog.DoModal() == IDCANCEL) ! 658: return FALSE; ! 659: ! 660: pDC = new CDC; ! 661: pDC->Attach(printDialog.GetPrinterDC()); ! 662: ! 663: xPage = pDC->GetDeviceCaps(HORZRES); ! 664: yPage = pDC->GetDeviceCaps(VERTRES); ! 665: ! 666: // The chart main window has to be disabled while printing so that ! 667: // the user can't change data. ! 668: // ! 669: EnableWindow(FALSE); ! 670: ! 671: // Set up the printer abort box and its window procedure control ! 672: // variables ! 673: // ! 674: bUserAbort = FALSE; ! 675: m_pPrintDlg = new CPrintDlgBox; ! 676: hPrintDlg = m_pPrintDlg->m_hWnd; ! 677: ! 678: if (pDC->SetAbortProc(lpfnAbortProc) < 0) ! 679: { ! 680: delete pDC; ! 681: return FALSE; ! 682: } ! 683: ! 684: #ifndef _NTWIN ! 685: if (pDC->StartDoc(szMessage) > 0) ! 686: #else ! 687: DOCINFO di; ! 688: di.cbSize = sizeof(di); ! 689: di.lpszDocName = szMessage; ! 690: di.lpszOutput = NULL; ! 691: if (pDC->StartDoc(&di) > 0) ! 692: #endif ! 693: { ! 694: oldX = m_cxClient; ! 695: m_cxClient = xPage; ! 696: oldY = m_cyClient; ! 697: m_cyClient = yPage; ! 698: ! 699: RenderChart(pDC); ! 700: ! 701: if (pDC->EndPage() > 0) ! 702: { ! 703: pDC->EndDoc(); ! 704: } ! 705: else ! 706: { ! 707: bError = TRUE; ! 708: } ! 709: } ! 710: else ! 711: { ! 712: bError = TRUE; ! 713: } ! 714: ! 715: m_cxClient = oldX; ! 716: m_cyClient = oldY; ! 717: ! 718: // Now that we're done, we can now allow the user access to the frame ! 719: // window again. bUserAbort is set in the AbortProc just before this ! 720: // function. ! 721: // ! 722: if (!bUserAbort) ! 723: { ! 724: EnableWindow(TRUE); ! 725: } ! 726: ! 727: delete pDC; ! 728: delete m_pPrintDlg; ! 729: ! 730: return !bError && !bUserAbort; ! 731: } ! 732: ! 733: // CmdFileSave: ! 734: // User wants to save current chart data in the current file ! 735: // ! 736: void CChartWnd::CmdFileSave() ! 737: { ! 738: if (!m_bUntitled) ! 739: { ! 740: SaveFile(FALSE); ! 741: UpdateMenu(); ! 742: } ! 743: } ! 744: ! 745: // CmdFileSaveAs: ! 746: // User wants to save current chart data in a named file ! 747: // ! 748: void CChartWnd::CmdFileSaveAs() ! 749: { ! 750: SaveFile(TRUE); ! 751: UpdateMenu(); ! 752: } ! 753: ! 754: // CmdFileOpen ! 755: // User wants to open an existing file and read in chart data ! 756: // ! 757: void CChartWnd::CmdFileOpen() ! 758: { ! 759: // Create data structure if there is none. ! 760: // ! 761: if (m_pChartObject != NULL) ! 762: { ! 763: if (m_pChartObject->m_bDirty) ! 764: { ! 765: if (MessageBox("Save existing data?", "Chart", ! 766: MB_YESNO | MB_ICONQUESTION) == IDYES) ! 767: { ! 768: SaveFile(m_bUntitled); ! 769: } ! 770: } ! 771: } ! 772: ! 773: // Get the data. ! 774: // ! 775: ReadFile(); ! 776: ! 777: // If read failed, or there's no data to read, clean up. ! 778: // ! 779: ! 780: if (!m_bChartSerializedOK) ! 781: { ! 782: // chart deserialization failed and chart is in an ! 783: // inconsistent state -- don't delete. Just null ! 784: // the pointer and suffer a memory leak. ! 785: ! 786: m_pChartObject = NULL; ! 787: } ! 788: else ! 789: { ! 790: if ((m_pChartObject->m_pChartData == NULL) || ! 791: m_pChartObject->m_pChartData->IsEmpty()) ! 792: { ! 793: delete m_pChartObject; ! 794: m_pChartObject = NULL; ! 795: } ! 796: } ! 797: ! 798: // Update the frame menu and client area ! 799: // ! 800: UpdateMenu(); ! 801: Invalidate(TRUE); ! 802: } ! 803: ! 804: // OnAbout: ! 805: // ! 806: void CChartWnd::OnAbout() ! 807: { ! 808: CModalDialog aboutBox("AboutBox"); ! 809: aboutBox.DoModal(); ! 810: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.