Annotation of mstools/mfc/samples/chart/chartwnd.cpp, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.