/***************************************************************************** * * Copyright (c) 1999, KL GROUP INC. All Rights Reserved. * http://www.klgroup.com * * This file is provided for demonstration and educational uses only. * Permission to use, copy, modify and distribute this file for * any purpose and without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies, and that the name of KL Group not be used in advertising * or publicity pertaining to this material without the specific, * prior written permission of an authorized representative of * KL Group. * * KL GROUP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. KL GROUP SHALL NOT BE LIABLE FOR ANY * DAMAGES SUFFERED BY USERS AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ // barsView.cpp : implementation of the CBarsView class // #include "stdafx.h" #include "bars.h" #include "och3dMFC.cpp" #include "oc_color.h" #include "barsDoc.h" #include "barsView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define BAR_LABEL_TIMER (1212) // Arbitrary timer value #define TEXT_HILITE_COLOR XrtColorRosyBrown #define BAR_HILITE_COLOR XrtColorLightSeaGreen static char* headers[] = { "Change the value of", "any bar by dragging it!", NULL }; static char* footers[] = { "No Bar Selected", NULL }; static char* header_ID_label[] = { "That's the header!", NULL }; static char* footer_ID_label[] = { "That's the footer!", NULL }; static Xrt3dXYColor barcolors[] = { { 0, -1, XrtColorBeige }, { 1, -1, XrtColorBlanchedAlmond }, { 2, -1, XrtColorTan }, NULL }; static Xrt3dLineStyle grid_style = { XRT3D_LPAT_SOLID, XrtColorCadetBlue, 2 }; ///////////////////////////////////////////////////////////////////////////// // CBarsView IMPLEMENT_DYNCREATE(CBarsView, CView) BEGIN_MESSAGE_MAP(CBarsView, CView) //{{AFX_MSG_MAP(CBarsView) ON_WM_SIZE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_TIMER() ON_COMMAND(ID_FONT_STROKE, OnFontStroke) ON_COMMAND(ID_FONT_TRUETYPE, OnFontTruetype) ON_UPDATE_COMMAND_UI(ID_FONT_STROKE, OnUpdateFontStroke) ON_UPDATE_COMMAND_UI(ID_FONT_TRUETYPE, OnUpdateFontTruetype) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CBarsView construction/destruction CBarsView::CBarsView() { m_pData = NULL; m_pLabel = NULL; m_nPickRow = -1; m_nPickCol = -1; m_nLastRow = -1; m_nLastCol = -1; m_bIsModifying = FALSE; } CBarsView::~CBarsView() { if (m_pData != NULL ) { // Free the chart data delete m_pData; } if( m_pLabel != NULL ) { // Free the chart label delete m_pLabel; } } BOOL CBarsView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CBarsView drawing void CBarsView::OnDraw(CDC* pDC) { CBarsDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here } ///////////////////////////////////////////////////////////////////////////// // CBarsView diagnostics #ifdef _DEBUG void CBarsView::AssertValid() const { CView::AssertValid(); } void CBarsView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CBarsDoc* CBarsView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CBarsDoc))); return (CBarsDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CBarsView message handlers BOOL CBarsView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { BOOL ret = CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); if (ret) { // create a chart window when the view is created ret = m_chart.Create("", WS_CHILD | WS_VISIBLE, rect, this, 0); if (ret) { m_pData = new CChart3DData("bars3d.dat"); ASSERT( m_pData != NULL ); if( m_pData->GetData() != NULL ) { m_chart.SetSurfaceData(*m_pData); } else { AfxMessageBox( "Data file bars3d.dat was not found!" ); ret = FALSE; } } } return (ret); } ///////////////////////////////////////////////////////////////////////////// // Update the size of the Chart when the window is resized ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if (IsWindow(m_chart.m_hWnd)) { // If the view has resize then resize the chart if it has been created m_chart.SetWindowPos(&wndTop, 0, 0, cx, cy, SWP_NOZORDER); } } ///////////////////////////////////////////////////////////////////////////// // Do all the setup of the Chart when window is updated for the first time ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnInitialUpdate() { CView::OnInitialUpdate(); // Batch all the updates to the Chart m_chart.SetRepaint(false); // Set the Chart type to bar m_chart.SetType( XRT3D_TYPE_BAR ); // Setup some colors m_chart.SetBackgroundColor(XrtColorLinen); m_chart.SetForegroundColor(XrtColorBlack); // Setup the borders m_chart.SetBorder(XRT3D_BORDER_3D_IN); m_chart.SetBorderWidth(2); // Setup the ChartArea m_chart.SetGraphBackgroundColor(XrtColorAntiqueWhite); m_chart.SetGraphBorder(XRT3D_BORDER_ETCHED_IN); m_chart.SetGraphBorderWidth(4); m_chart.SetGraphBackgroundColor(XrtColorAntiqueWhite); m_chart.SetDataAreaBackgroundColor(XrtColorLemonChiffon); // Setup the scale m_chart.SetXScale(2); m_chart.SetYScale(2); // Setup the Axis m_chart.SetAxisStrokeFont(XRT3D_SF_ROMAN_SIMPLEX); m_chart.SetAxisStrokeSize(60); m_chart.SetXAxisTitle("Rows"); m_chart.SetYAxisTitle("Columns"); m_chart.SetAxisTitleStrokeFont(XRT3D_SF_ROMAN_TRIPLEX); m_chart.SetAxisTitleStrokeSize(100); // Turn on all the Axis grid lines m_chart.SetXGridLines(XRT3D_XY_PLANE | XRT3D_XZ_PLANE); m_chart.SetYGridLines(XRT3D_XY_PLANE | XRT3D_YZ_PLANE); m_chart.SetZGridLines(XRT3D_XZ_PLANE | XRT3D_YZ_PLANE); // Set the gridline styles m_chart.SetXGridLineStyle(&grid_style); m_chart.SetYGridLineStyle(&grid_style); m_chart.SetZGridLineStyle(&grid_style); // Create an Arial bold font for the header CFont headerfont; headerfont.CreateFont(-20, 0, 0, 0, FW_BOLD, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial"); // Setup the header m_chart.SetHeaderStrings(headers); m_chart.SetHeaderBorder(XRT3D_BORDER_ETCHED_OUT); m_chart.SetHeaderBorderWidth(4); m_chart.SetHeaderBackgroundColor(XrtColorLightGoldenrod); m_chart.SetHeaderFont(headerfont); // Create a Times New Roman font for the footer CFont footerfont; footerfont.CreateFont(-14, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Times New Roman"); // Setup the footer m_chart.SetFooterStrings(footers); m_chart.SetFooterBorder(XRT3D_BORDER_SHADOW); m_chart.SetFooterBorderWidth(4); m_chart.SetFooterBackgroundColor(XrtColorBlanchedAlmond); m_chart.SetFooterFont(footerfont); // Enable the bar colors ... bar colors will be invisible unless we do this! m_chart.SetDrawShaded(TRUE); //Add colors to the bars and do the entire column for each row Xrt3dSetXYColor(m_chart.m_hChart, 0, -1, XrtColorBeige ); Xrt3dSetXYColor(m_chart.m_hChart, 1, -1, XrtColorBlanchedAlmond ); Xrt3dSetXYColor(m_chart.m_hChart, 2, -1, XrtColorTan ); // Go back to normal Chart updates m_chart.SetRepaint(true); // Create a chart label and set it up m_pLabel = new CChart3DTextArea( &m_chart ); if( m_pLabel != NULL ) { m_pLabel->SetShow(FALSE); m_pLabel->SetAttachMethod( XRT3D_ATTACH_PIXEL ); m_pLabel->SetAttachPixelX(0); m_pLabel->SetAttachPixelY(0); m_pLabel->SetOffsetX(0); m_pLabel->SetOffsetY(0); m_pLabel->SetBackgroundColor( TEXT_HILITE_COLOR ); m_pLabel->SetBorder(XRT3D_BORDER_SHADOW); m_pLabel->SetBorderWidth(4); } UpdateFooter(0, 0); } ///////////////////////////////////////////////////////////////////////////// // Respond to the user pressing the left-mouse button while over the Chart ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnLButtonDown(UINT nFlags, CPoint point) { // If the user is modifying the Chart, get out of here if (m_bIsModifying) { return; } // If only the left-mouse button has been pressed then make a note of it for // for future use in dragging a bar to a new value if (((nFlags & MK_LBUTTON) != 0) && ((nFlags & MK_SHIFT) == 0)) { Xrt3dPickResult pickResult; m_rgnRegion = m_chart.Pick(point.x, point.y, &pickResult); if ((m_rgnRegion == XRT3D_RGN_IN_GRAPH) && (pickResult.xindex >= 0) && (pickResult.yindex >= 0) && (pickResult.distance == 0)) { m_nPickRow = pickResult.xindex; m_nPickCol = pickResult.yindex; } } CView::OnLButtonDown(nFlags, point); } ///////////////////////////////////////////////////////////////////////////// // Respond to the user letting the left-mouse button up while over the Chart ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnLButtonUp(UINT nFlags, CPoint point) { m_nPickRow = -1; m_nPickCol = -1; CView::OnLButtonUp(nFlags, point); } ///////////////////////////////////////////////////////////////////////////// // Respond to the user moving the mouse over the Chart ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnMouseMove(UINT nFlags, CPoint point) { // If the user is modifying the Chart, get out of here if (m_bIsModifying) { return; } double Value; m_rgnOldRegion = m_rgnRegion; // If we are dragging a bar, then update the bar value and the footer information if ((m_nPickRow != -1) && (m_nPickCol != -1)) { m_chart.SetRepaint(false); _ASSERT( m_pData != NULL ); Value = Xrt3dComputeZValue( m_chart.m_hChart, m_nPickRow, m_nPickCol, point.x, point.y); if (Value > 15) { Value = 15; } if (Value < -15) { Value = -15; } m_pData->SetValue(m_nPickRow, m_nPickCol, Value); UpdateFooter(m_nPickRow, m_nPickCol); m_chart.SetRepaint(true); } // If we are over either the header or footer, highlight it for a short period of time else { Xrt3dPickResult pickResult; m_rgnRegion = m_chart.Pick(point.x, point.y, &pickResult); if (((m_rgnRegion == XRT3D_RGN_IN_HEADER) || (m_rgnRegion == XRT3D_RGN_IN_FOOTER)) && (m_rgnRegion != m_rgnOldRegion)) { switch (m_rgnRegion) { case XRT3D_RGN_IN_HEADER: RemoveHiLite(); AddHiLite(point.x, point.y); break; case XRT3D_RGN_IN_FOOTER: RemoveHiLite(); AddHiLite(point.x, point.y); break; } } // The user has moved off the Chart, so remove the highlight off the currently highlighted bar else { if ((m_rgnRegion != XRT3D_RGN_IN_GRAPH) || (pickResult.xindex < 0) || (pickResult.yindex < 0) && (pickResult.distance != 0)) { if ((m_nLastRow > -1) && (m_nLastCol > -1)) { // Specifiying XRT3D_DEFAULT_COLOR means "remove this color entry" Xrt3dSetXYColor(m_chart.m_hChart, m_nLastRow, m_nLastCol, XRT3D_DEFAULT_COLOR ); } m_nLastRow = -1; m_nLastCol = -1; UpdateFooter(m_nLastRow, m_nLastCol); } // The user has moved off of the current bar so remove the highlight from it and highlight // the newly 'selected' bar else { if ((pickResult.xindex != m_nLastRow) || (pickResult.yindex != m_nLastCol)) { m_chart.SetRepaint(false); if ((m_nLastRow > -1) && (m_nLastCol > -1)) { // Specifiying XRT3D_DEFAULT_COLOR means "remove this color entry" Xrt3dSetXYColor(m_chart.m_hChart, m_nLastRow, m_nLastCol, XRT3D_DEFAULT_COLOR ); } if ((pickResult.xindex >= 0) && (pickResult.yindex >= 0)) { // Add a color entry for the specific bar in question Xrt3dSetXYColor(m_chart.m_hChart, pickResult.xindex, pickResult.yindex, BAR_HILITE_COLOR ); } m_nLastRow = pickResult.xindex; m_nLastCol = pickResult.yindex; UpdateFooter(m_nLastRow, m_nLastCol); m_chart.SetRepaint(true); } } } } CView::OnMouseMove(nFlags, point); } ///////////////////////////////////////////////////////////////////////////// // Update the information in the footer ///////////////////////////////////////////////////////////////////////////// void CBarsView::UpdateFooter(long Row, long Col) { char szBuffer[80]; char* myfooter[] = { szBuffer, NULL }; double Value; if ((Row > -1) && (Col > -1)) { _ASSERT( m_pData != NULL ); _ASSERT( m_pData->GetData() != NULL ); // Protect ourselves in case somebody calls us with bad Row/Col data if ((Row < m_pData->GetNumX()) && (Col < m_pData->GetNumY())) { Xrt3dData* data = m_pData->GetData(); Value = m_pData->GetValue(Row, Col); sprintf(szBuffer, "Bar Index(%d, %d) = %2.2f", Row+1, Col+1, Value); m_chart.SetFooterStrings(myfooter); } } else { // There's always one line of text in the footers, so just compare them. if ( !strcmp(*m_chart.GetFooterStrings(), *footers) ) { m_chart.SetFooterStrings(footers); } } } ///////////////////////////////////////////////////////////////////////////// // Add a HiLite to the Header/Footer ///////////////////////////////////////////////////////////////////////////// void CBarsView::AddHiLite(long x, long y) { switch (m_rgnRegion) { case XRT3D_RGN_IN_HEADER: m_chart.SetHeaderBackgroundColor(TEXT_HILITE_COLOR); if( m_pLabel != NULL ) { m_pLabel->SetStrings(header_ID_label); m_pLabel->SetAttachPixelX( m_chart.GetHeaderX() + m_chart.GetHeaderWidth() ); m_pLabel->SetAttachPixelY( m_chart.GetHeaderY() + m_chart.GetHeaderHeight() ); m_pLabel->SetOffsetX(25); m_pLabel->SetOffsetY(25); } break; case XRT3D_RGN_IN_FOOTER: m_chart.SetFooterBackgroundColor(TEXT_HILITE_COLOR); if( m_pLabel != NULL ) { m_pLabel->SetStrings(footer_ID_label); m_pLabel->SetAttachPixelX( m_chart.GetFooterX() + m_chart.GetFooterWidth() ); m_pLabel->SetAttachPixelY( m_chart.GetFooterY() ); m_pLabel->SetOffsetX(25); m_pLabel->SetOffsetY(-25); } break; } if( m_pLabel != NULL ) { m_pLabel->SetShow(TRUE); } SetTimer(BAR_LABEL_TIMER, 1500, NULL); UpdateFooter(0, 0); } ///////////////////////////////////////////////////////////////////////////// // Remove the HiLite ///////////////////////////////////////////////////////////////////////////// void CBarsView::RemoveHiLite(void) { m_chart.SetRepaint(false); if( m_pLabel != NULL ) { m_pLabel->SetShow(FALSE); } KillTimer(BAR_LABEL_TIMER); // We neither know nor care which one it was, just set them both back m_chart.SetHeaderBackgroundColor(XrtColorLightGoldenrod); m_chart.SetFooterBackgroundColor(XrtColorBlanchedAlmond); UpdateFooter(0, 0); m_chart.SetRepaint(true); } ///////////////////////////////////////////////////////////////////////////// // Respond to the Timer ///////////////////////////////////////////////////////////////////////////// void CBarsView::OnTimer(UINT nIDEvent) { if( nIDEvent == BAR_LABEL_TIMER) { // Remove the HiLite from the Header/Footer RemoveHiLite(); } CView::OnTimer(nIDEvent); } void CBarsView::OnFontStroke() { m_chart.SetUseTruetype(FALSE); } void CBarsView::OnUpdateFontStroke(CCmdUI* pCmdUI) { pCmdUI->SetCheck(!m_chart.GetUseTruetype()); } void CBarsView::OnFontTruetype() { m_chart.SetUseTruetype(TRUE); } void CBarsView::OnUpdateFontTruetype(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_chart.GetUseTruetype()); }