/***************************************************************************** * * 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. */ // chlabelsView.cpp : implementation of the CChartLabelsView class // #include "stdafx.h" #include #include "chlabels.h" #include "chlabelsDoc.h" #include "chlabelsView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "Axis.h" #include "AxisCollection.h" #include "Bar.h" #include "Border.h" #include "ChartArea.h" #include "Chart2DData.h" #include "ChartGroup.h" #include "ChartGroupCollection.h" #include "ChartLabel.h" #include "ChartLabelCollection.h" #include "ChartStyle.h" #include "ChartStyleCollection.h" #include "Coord.h" #include "DataIndex.h" #include "DerivedDouble.h" #include "DerivedLong.h" #include "FillStyle.h" #include "Font.h" #include "GridLines.h" #include "Interior.h" #include "Label.h" #include "LabelCollection.h" #include "LineStyle.h" #include "Legend.h" #include "Location.h" #include "PlotArea.h" #include "Title.h" #include "View3d.h" #include "2dConst.h" #include "oc_color.h" #define MAX_STR_LEN 200 const double ocHugeValue = 1E+308; ///////////////////////////////////////////////////////////////////////////// // CChartLabelsView IMPLEMENT_DYNCREATE(CChartLabelsView, CFormView) BEGIN_MESSAGE_MAP(CChartLabelsView, CFormView) //{{AFX_MSG_MAP(CChartLabelsView) ON_WM_SIZE() ON_BN_CLICKED(IDC_CLEARLABELS_BUTTON, OnClearLabelsButton) ON_WM_TIMER() ON_BN_CLICKED(IDC_LABEL1, OnLabel1) ON_BN_CLICKED(IDC_LABEL2, OnLabel2) ON_BN_CLICKED(IDC_LABEL4, OnLabel4) ON_BN_CLICKED(IDC_LABEL3, OnLabel3) ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CChartLabelsView construction/destruction CChartLabelsView::CChartLabelsView() : CFormView(CChartLabelsView::IDD) { //{{AFX_DATA_INIT(CChartLabelsView) //}}AFX_DATA_INIT // initialize member data // Globals used to keep track of which bar is being dragged m_SaveSeries = 0; // Value for which bar we are on m_SavePoint = 0; // Value for where we are along a bar m_Interior = NULL; // Set this up to allow us to make it easier to check the status of the interior of an object m_SaveColor = 0; // Holding tank for the background color of a region while it is highlighted // Globals for the colors of the different regions m_HeaderColor = 0; m_FooterColor = 0; m_LegendColor = 0; // Globals for the current region m_Region =0; // Value for what region the mouse cursor is current in m_OldRegion = 0; // Holding tank for the region value m_ChartModify = false; // Don't do some events when this is true m_LabelCount = 0; } CChartLabelsView::~CChartLabelsView() { } void CChartLabelsView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); //{{AFX_DATA_MAP(CChartLabelsView) DDX_Control(pDX, IDC_CHART2D1, m_chart); //}}AFX_DATA_MAP } BOOL CChartLabelsView::PreCreateWindow(CREATESTRUCT& cs) { bool temp; temp = (CFormView::PreCreateWindow(cs) == 1); // this line (and it's buddy in mainframe.cpp) kill the sunken window effect cs.dwExStyle ^= WS_EX_CLIENTEDGE; return temp; } void CChartLabelsView::OnInitialUpdate() { // convienience variables CChartLabel label; m_MyLabel1.SubclassDlgItem(IDC_LABEL1, this); m_MyLabel2.SubclassDlgItem(IDC_LABEL2, this); m_MyLabel3.SubclassDlgItem(IDC_LABEL3, this); m_MyLabel4.SubclassDlgItem(IDC_LABEL4, this); CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // Let all the functions do their thing m_ChartModify = false; // Set the initial Chart Settings InitialChartSetup(); // Store the colors chosen for the 3 chart regions m_HeaderColor = m_chart.GetHeader().GetInterior().GetBackgroundColor(); m_FooterColor = m_chart.GetFooter().GetInterior().GetBackgroundColor(); m_LegendColor = m_chart.GetLegend().GetInterior().GetBackgroundColor(); // Setup the Chart Label ahead of time to make the updates to // it faster when the mouse is dragged over the bars label = m_chart.GetChartLabels().Add(); // Batch everything for better performance label.SetIsBatched(true); label.SetName("OnBar"); label.GetText().SetText(""); label.GetBorder().SetType(oc2dBorderNone); label.SetAttachMethod(oc2dAttachDataIndex); label.GetAttachDataIndex().SetSeries(1L); label.GetAttachDataIndex().SetPoint(1L); // Leave some space between the bar and the label label.SetOffset(10L); // Set back to the normal operation label.SetIsBatched(false); } ///////////////////////////////////////////////////////////////////////////// // CChartLabelsView diagnostics #ifdef _DEBUG void CChartLabelsView::AssertValid() const { CFormView::AssertValid(); } void CChartLabelsView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } CChlabelsDoc* CChartLabelsView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CChlabelsDoc))); return (CChlabelsDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CChartLabelsView message handlers void CChartLabelsView::OnSize(UINT nType, int cx, int cy) { CFormView::OnSize(nType, cx, cy); CSize mySize(cx,cy); CRect myRect; // check to see if the chart window has been created yet if (IsWindow(m_chart.m_hWnd)) { // Get the control area m_chart.GetClientRect(myRect); // Debugging info TRACE ("\nleft = %d\nright = %d\ntop = %d\nbottom = %d\n\n", myRect.left, myRect.right, myRect.top, myRect.bottom); TRACE ("\ncx = %d\ncy = %d\n\n", cx, cy); // Match the graph to the size of the form. if (cx > 36) { // Using 36 to keep a 18 pixel border on each side of the chart myRect.right = cx - 36; } else { myRect.right = 5; } if (cy > 40) { // Using 60 becuase the top of the control is at 40 pixels from the top and // we need a border of 20 pixels at the bottom myRect.bottom = cy - 56; } else { myRect.bottom = 5; } this->SetScaleToFitSize(mySize); m_chart.MoveWindow(18, 46, myRect.right, myRect.bottom); } } // Helper Function to Initialize Chart Data // In the VB version, this is done in the 'Property Pages' that you seen when right clicking on // the control in the form void CChartLabelsView::InitialChartSetup(void) { // Local Convienience Variables CChart2DData data; CLabelCollection labels; VARIANT va; // needed for setting labels CTitle title; COleCurrency hFontSize; // needed for setting font sizes CLegend legend; CChartArea chartArea; CAxis axis; // Turn on Double Buffering (which is the default) m_chart.SetIsDoubleBuffered(true); // Change the BorderWidth m_chart.GetBorder().SetWidth(4L); // Change the interior Color m_chart.GetInterior().SetBackgroundColor(ocColorLightSlateGray); // change X axis attributes axis = m_chart.GetChartArea().GetAxes().GetItem(COleVariant(1L)); hFontSize.SetCurrency(12, 0); axis.GetFont().SetSize(hFontSize); axis.SetAnnotationMethod(oc2dAnnotatePointLabels); // change Y axis attributes axis = m_chart.GetChartArea().GetAxes().GetItem(COleVariant(2L)); axis.GetTitle().SetText("Drag Bars to Change Value"); // change the Y axis precision (i.e. units to be displayed) axis.GetPrecision().SetValue(-1); // Change the Chart Type m_chart.GetChartGroups().GetItem(COleVariant(1L)).SetChartType(oc2dTypeBar); // Setup the Chart Series Data data = m_chart.GetChartGroups().GetItem(COleVariant(1L)).GetData(); data.SetLayout(oc2dDataArray); data.SetNumSeries(4L); data.SetNumPoints(1L, 2L); data.SetX(1, 1, 0); data.SetX(1, 2, 1); // the data double dataArr[4][2] = { {6, 15 }, {15, 7 }, {24.2, 11 }, {4.6, 15.1} }; for (int row=1; row<=4; row++) { for (int col=1; col<=2; col++) { data.SetY(row, col, dataArr[row-1][col-1]); TRACE("dataArr[%d][%d] = %f\n", row-1, col-1, dataArr[row-1][col-1]); TRACE("data.GetY(%d, %d)=%f", row, col, data.GetY(row, col)); } } // Change Cluster Width of Bars m_chart.GetChartArea().GetBar().SetClusterWidth(90); // Set The Chart Labels VariantInit(&va); va.vt = VT_I4; labels = m_chart.GetChartGroups().GetItem(COleVariant(1L)).GetPointLabels(); va.lVal = labels.GetCount() + 1; labels.Add("Group 2", va); va.lVal = labels.GetCount() + 1; labels.Add("Group 1", va); // Set The Series Labels VariantInit(&va); va.vt = VT_I4; labels = m_chart.GetChartGroups().GetItem(COleVariant(1L)).GetSeriesLabels(); va.lVal = labels.GetCount() + 1; labels.Add("Alpha", va); va.lVal = labels.GetCount() + 1; labels.Add("Beta", va); va.lVal = labels.GetCount() + 1; labels.Add("Gamma", va); va.lVal = labels.GetCount() + 1; labels.Add("Delta", va); // make the chart horizontal chartArea = m_chart.GetChartArea(); chartArea.SetIsHorizontal(true); // Interior color chartArea.GetInterior().SetBackgroundColor(RGB(0xbc,0xc6,0xd0)); // plot area color chartArea.GetPlotArea().GetInterior().SetBackgroundColor(ocColorAliceBlue); // 3d effects chartArea.GetView3D().SetDepth(10); chartArea.GetView3D().SetElevation(10); chartArea.GetView3D().SetRotation(25); // chart area border chartArea.GetBorder().SetType(oc2dBorderShadow); // --- Set The Header Up (which is of type CTitle) // text title = m_chart.GetHeader(); title.GetText().SetText("Click one of the above labels,\nthen click a bar on the chart."); // border properties title.GetBorder().SetWidth(3); title.GetBorder().SetType(oc2dBorder3DOut); // color title.GetInterior().SetBackgroundColor(ocColorBisque); title.GetInterior().SetForegroundColor(ocColorBlack); // font hFontSize.SetCurrency(12, 0); title.GetFont().SetSize(hFontSize); title.GetFont().SetBold(true); // --- Set The Footer Chart Label Up (which is of type CTitle) // text title = m_chart.GetFooter(); title.GetText().SetText("Total # of ChartLabels: 0"); // color title.GetInterior().SetForegroundColor(ocColorBlanchedAlmond); // font title.GetFont().SetSize(hFontSize); title.GetFont().SetBold(true); // --- Set the Legend Up (which is of type CLegend) legend = m_chart.GetLegend(); // border legend.GetBorder().SetWidth(3); legend.GetBorder().SetType(oc2dBorder3DOut); // interior color legend.GetInterior().SetBackgroundColor(ocColorLightYellow); // font legend.GetFont().SetBold(true); legend.GetFont().SetSize(hFontSize); } void CChartLabelsView::OnClearLabelsButton() { // Get rid of all the ChartLabels, and update the Footer. //Batch screen paints for better performance m_chart.SetIsBatched(true); // Loop through and remove all the added labels except the label for the bars for (long i=m_chart.GetChartLabels().GetCount(); i>=2; i--) { // Remove the label from the chart m_chart.GetChartLabels().Remove(COleVariant(i)); } // Go back to normal screen updates m_chart.SetIsBatched(false); // Update the info in the footer line UpdateFooter(); } // Convienience function to update the Text in the Footer void CChartLabelsView::UpdateFooter (void) { // Update the # of labels in use at the bottom of the Chart2D1. // build the string to ouptut to the footer. // Subtract 1 from the count because we always have the label for the bars active CString str; str.Format(_T("Total # of ChartLabels: %ld"), m_chart.GetChartLabels().GetCount() - (1 - m_LabelCount)); // set the footer text value m_chart.GetFooter().GetText().SetText(str); } // Add a Chart Highlight to a region void CChartLabelsView::AddHilite(long px, long py) { // Add a ChartLabel that highlights a particular region. // Its only around for a short time. Cancel any previous highlight first. long hiliteColor; // Value for the highlight color CChartLabel label; // Value for making it easier to deal with the label itself //Set the Highlight Color hiliteColor = ocColorRosyBrown; switch (m_Region) { // Check to make sure we are in one of the 3 regions case oc2dRegionInLegend : case oc2dRegionInHeader : case oc2dRegionInFooter : // Check to make sure there is some type of a background to highlight if ( !(m_Interior == NULL) ) { // Set the Interior of the selected region to the highlight color m_Interior.SetBackgroundColor(hiliteColor); } break; } // end of case // Set up to deal with the labels on the chart label = m_chart.GetChartLabels().Add(); // Batch everything for even faster processing label.SetIsBatched(true); // Depending on where we are, do the appropriate stuff switch (m_Region) { // Are we in the Legend? case oc2dRegionInLegend : label.GetText().SetText("That's the legend!"); // This is the displayed Text label.SetAttachMethod(oc2dAttachCoord); // Set the method of the label attachment label.GetAttachCoord().SetX(m_chart.GetLegend().GetLocation().GetLeft().GetValue() ); // Sets the actual X-axis location for the label label.GetAttachCoord().SetY(m_chart.GetLegend().GetLocation().GetTop().GetValue() ); // Sets the actual Y-axis location for the label label.SetAnchor(oc2dAnchorNorthWest); // Sets the anchor point for where the label is going to be label.GetInterior().SetBackgroundColor(hiliteColor); // Sets the background color of the label to the same as the background color of the region break; // Are we in the Header? case oc2dRegionInHeader : label.GetText().SetText("That's the header!"); label.SetAttachMethod(oc2dAttachCoord); label.GetAttachCoord().SetX(m_chart.GetHeader().GetLocation().GetLeft().GetValue() + m_chart.GetHeader().GetLocation().GetWidth().GetValue() ); label.GetAttachCoord().SetY(m_chart.GetHeader().GetLocation().GetTop().GetValue() + m_chart.GetHeader().GetLocation().GetHeight().GetValue() ); label.SetAnchor(oc2dAnchorSouthEast); label.GetInterior().SetBackgroundColor(hiliteColor); break; // Are we in the Footer? case oc2dRegionInFooter : label.GetText().SetText("That's the footer!"); label.SetAttachMethod(oc2dAttachCoord); label.GetAttachCoord().SetX(m_chart.GetFooter().GetLocation().GetLeft().GetValue() + m_chart.GetFooter().GetLocation().GetWidth().GetValue() ); label.GetAttachCoord().SetY(m_chart.GetFooter().GetLocation().GetTop().GetValue() ); label.SetAnchor(oc2dAnchorNorthEast); label.GetInterior().SetBackgroundColor(hiliteColor); break; // Don't know where we are! default : label.GetText().SetText("You Missed!"); label.SetAttachMethod(oc2dAttachCoord); label.GetAttachCoord().SetX(px); label.GetAttachCoord().SetY(py); label.SetAnchor(oc2dAnchorCenter); label.GetInterior().SetBackgroundColor(ocColorLightSteelBlue); break; } // end switch // set some generic attributes label.SetName("Region"); // Setup the label as a region label label.SetOffset(20); // Give it some room to draw a pointer line label.GetBorder().SetType(oc2dBorderShadow); // Shadow the border around the region label.GetBorder().SetWidth(4); // Setup an easy-to-see border size label.SetIsConnected(true); // Draw the line between the label and the region label.SetIsBatched(false); // 'Do the update so its all visible // Timer ID 1 is used for Chart Highlights this->SetTimer(1, 1500, NULL); // Remove the label in 1.5 seconds // Update the info in the footer line UpdateFooter(); } // Determine if a label exists, given it's name long CChartLabelsView::FindLabel(CString name) { // Determine if there is a chartlabel with this name, and return it's COleVariant # // return -1 otherwise CChartLabelCollection labels; // Value for making it easier to deal with the labels labels = m_chart.GetChartLabels(); for (long curLabel = 1; curLabel <= labels.GetCount(); curLabel++) { if (labels.GetItem(COleVariant(curLabel)).GetName() == name) { // we have found a match return curLabel; } } return -1; } // Remove a label void CChartLabelsView::RemoveLabel(CString name) { // Remove the label, if there is one of this name. long labelNum = this->FindLabel(name); // Call the function HasLabel and remove a label if one exists if (labelNum != -1) { if (name != "OnBar") { // Remove the label from the chart m_chart.GetChartLabels().Remove(COleVariant(labelNum)); } else { m_LabelCount = 0; m_chart.GetChartLabels().GetItem(COleVariant(labelNum)).GetText().SetText(""); } } } // Remove a Hilite void CChartLabelsView::RemoveHilite(void) { // Removes a hilite, if there is one. Call the timer to remove it, and disable the timer. OnTimer(1); // Call the Timer Event to clear the highlight this->KillTimer(1); // Disable Timer as it is not needed now } void CChartLabelsView::OnTimer(UINT nIDEvent) { // Handle the WM_TIMER Message CFormView::OnTimer(nIDEvent); switch (nIDEvent) { case 1: // Remove the ChartLabel on the header/footer/legend. // Enable batch mode for even better performance m_chart.SetIsBatched(true); // Remove any region labels current visible on the screen RemoveLabel("Region"); // Disable Timer1 as it is no longer needed this->KillTimer(1); // If there is something in the interior than save the color of it if (m_Interior != NULL) { m_Interior.SetBackgroundColor(m_SaveColor); } // Update the info in the footer line UpdateFooter(); // Return to normal screen updates m_chart.SetIsBatched(false); break; case 2: // Used to remove the ChartLabel that shows the bars present value. // Keep label around while dragging bar if (m_SaveSeries == 0 && m_SavePoint == 0) { // Remove the label thats on the bar RemoveLabel("OnBar"); // Disable the Timer as it is not needed KillTimer(2); // Update the info in the footer line UpdateFooter(); } } } BEGIN_EVENTSINK_MAP(CChartLabelsView, CFormView) //{{AFX_EVENTSINK_MAP(CChartLabelsView) ON_EVENT(CChartLabelsView, IDC_CHART2D1, -606 /* MouseMove */, OnMouseMoveChart2d1, VTS_I2 VTS_I2 VTS_I4 VTS_I4) ON_EVENT(CChartLabelsView, IDC_CHART2D1, 2 /* ModifyStart */, OnModifyStartChart2d1, VTS_PBOOL) ON_EVENT(CChartLabelsView, IDC_CHART2D1, 1 /* ModifyEnd */, OnModifyEndChart2d1, VTS_NONE) ON_EVENT(CChartLabelsView, IDC_CHART2D1, -605 /* MouseDown */, OnMouseDownChart2d1, VTS_I2 VTS_I2 VTS_I4 VTS_I4) ON_EVENT(CChartLabelsView, IDC_CHART2D1, -607 /* MouseUp */, OnMouseUpChart2d1, VTS_I2 VTS_I2 VTS_I4 VTS_I4) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP() void CChartLabelsView::OnMouseMoveChart2d1(short Button, short Shift, long X, long Y) { // Handle the WM_MOUSEMOVE Message /* * Whenever the mouse moves, do one of the following: * - if over header/footer/legend, make its color a little lighter; * if not over one of these areas, restore it to its original color * - if over a particular bar, create a ChartLabel which displays its * value * - if we're dragging a bar, update the data value, and update * the ChartLabel that is on the bar */ // Setup the required variables long px, py; long Series; long Point; long Distance = 0; double vx, vy; CChartGroup chGroup; CChartLabel label; CString str; // Check to make sure we are allowed to do our thing if (!m_ChartModify) { px = X; // Get the current X position of the mouse py = Y; // Get the current Y position of the mouse if (m_SaveSeries == 0 && m_SavePoint == 0) { // We're not dragging a bar: check which area its over, // and highlight it. If we're not in one of the three areas, // restore the color of the region we were last in // Store the Current Region m_OldRegion = m_Region; // Get the current region the mouse is in m_Region = m_chart.GetChartGroups().GetItem(COleVariant(1L)).CoordToDataIndex(px, py, oc2dFocusX, &Series, &Point, &Distance); // If we are in one of the 3 regions remove any that are currently highlighted // and then put the highlight on the region the mouse is currently in if ( (m_Region == oc2dRegionInLegend || m_Region == oc2dRegionInHeader || m_Region == oc2dRegionInFooter) && (m_OldRegion != m_Region) ) { switch (m_Region) { // we're in the header case oc2dRegionInHeader : RemoveHilite(); m_SaveColor = m_HeaderColor; m_Interior = m_chart.GetHeader().GetInterior(); AddHilite(px, py); break; // we're in the footer case oc2dRegionInFooter : RemoveHilite(); m_SaveColor = m_FooterColor; m_Interior = m_chart.GetFooter().GetInterior(); AddHilite (px, py); break; // we're in the legend case oc2dRegionInLegend : RemoveHilite(); m_SaveColor = m_LegendColor; m_Interior = m_chart.GetLegend().GetInterior(); AddHilite(px, py); break; } // end switch } // end of if we are in a header or footer or legend if ( (Series > 0 && Point > 0) && (Distance < 5) ) { // Some bar has been chosen. If we aren't counting down to // remove remove the current lablel, then move on and update // the label, otherwise see if we are on the same bar and reset // the timer so the label doesn't flick on and off after three // seconds have passed. // If the timer is already not active, then continue on // get the label called "OnBar" CChartLabel label = m_chart.GetChartLabels().GetItem(COleVariant(this->FindLabel("OnBar")) ); // Instead of checking if the Timer is Active (like the VB version does), // We're checking if the label "OnBar" has some text associated with it. if (label.GetText().GetText() != "") { // If we are on the same bar, reset the timer and get out of here if (label.GetAttachDataIndex().GetSeries() == Series && label.GetAttachDataIndex().GetPoint() == Point) { // reset the timer because the user hasn't moved the mouse off the bar yet KillTimer(2); SetTimer(2, 3000, NULL); return; } } // What is the value of the bar vy = m_chart.GetChartGroups().GetItem(COleVariant(1L)).GetData().GetY(Series, Point); // Format 'vy' with one decimal point accuracy str.Format(_T("%.1f"), vy ); label.SetIsBatched(true); label.GetText().SetText(str); label.GetAttachDataIndex().SetSeries(Series); label.GetAttachDataIndex().SetPoint(Point); // Check if we are we postive or negative? // Depending on negative/positive, set the anchor to keep the label inside the bar if (vy < 0) { label.SetAnchor(oc2dAnchorEast); } else { label.SetAnchor(oc2dAnchorWest); } label.SetIsBatched(false); this->SetTimer(2, 3000, NULL); // Remove the label in 3 seconds m_LabelCount = 1; // Update the info in the footer line UpdateFooter(); } // end of if we are in a bar on the chart } else { // We're dragging a bar, so change its value, and update the // OnBar chartLabel with its value if (Distance < 5) { // If we are within 5 pixels, go ahead and drag chGroup = m_chart.GetChartGroups().GetItem(COleVariant(1L)); chGroup.CoordToDataCoord(px, py, &vx, &vy); // Make sure the value we are at is visible value (Hole values are invisible) if (vy != ocHugeValue) { // Batch the updates to the chart m_chart.SetIsBatched(true); // Limit the drag value if (vy > 100) { vy = 100; } else if (vy < -100) { vy = -100; } // Set the new size of the bar chGroup.GetData().SetY(m_SaveSeries, m_SavePoint, vy); label = m_chart.GetChartLabels().GetItem(COleVariant(FindLabel("OnBar")) ); label.SetIsBatched(true); // Update the bar label to reflect the new value // Format 'vy' with one decimal point accuracy str.Format(_T("%.1f"), DBL_DIG, vy ); label.GetText().SetText( str ); // Are we postive or negative? // Depending on negative/positive, set the anchor // to keep the label inside the bar if (vy < 0) { label.SetAnchor(oc2dAnchorEast); } else { label.SetAnchor(oc2dAnchorWest); } label.SetIsBatched(false); // Go back to normal chart updates m_chart.SetIsBatched(false); } // end if } // end if } // end else } // end of if (!m_ChartModify) } void CChartLabelsView::OnModifyStartChart2d1(BOOL FAR* IsOK) { // Tell the other functions to shutdown while a special function is in use. // Tell all the other functions to stop working m_ChartModify = true; } void CChartLabelsView::OnModifyEndChart2d1() { // Let the rest of the functions go back to doing their thing. // Reset the Special Functions Flag m_ChartModify = false; } void CChartLabelsView::OnMouseDownChart2d1(short Button, short Shift, long X, long Y) { // Setup the required variables long px, py; long Series, Point; long Distance; // If the mouse goes down on a bar, initialize the globals save the series and point, // Check to make sure we are allowed to do our thing if (!m_ChartModify) { /* * Shift = 0 when there are no extra keys being pressed * Shift = 1 when the Shift Key is being pressed * Shift = 2 when the Ctrl Key is being pressed * Shift = 3 when the Ctrl+Shift Keys are pressed together * Shift = 4 when the Alt Key is being pressed * Shift = 5 when the Alt+Shift Keys are pressed together * Shift = 6 when the Ctrl+Alt Keys are pressed together * * Button = 0 when there are no mouse buttons being pressed * Button = 1 when the left mouse button is being pressed * Button = 2 when the right mouse button is being pressed * Button = 4 when the middle mouse button is being pressed */ //Get the current location of the mouse px = X; py = Y; m_chart.GetChartGroups().GetItem(COleVariant(1L)).CoordToDataIndex(px, py, oc2dFocusX, &Series, &Point, &Distance); // Make sure a bar-drag will only happen with no keys pressed using the // left button and we are very close to the bar if (Button == 1 && Shift == 0 && Distance < 5) { // if we are on a bar, backup the current values if (Series > 0 && Point > 0) { m_SaveSeries = Series; m_SavePoint = Point; } } } } void CChartLabelsView::OnMouseUpChart2d1(short Button, short Shift, long X, long Y) { // temporary variables for adding labels CChartLabel newLabel; CChartLabelCollection labels; COleCurrency hFontSize; LPCTSTR labelText; long Series, Point, Distance; bool needCreate = true; // Not dragging a bar anymore, so reset globals. // Check to make sure we are allowed to do our thing if (!m_ChartModify) { // Reset the backup copies of the series and the point m_SaveSeries = 0; m_SavePoint = 0; // Remove the label in 3 seconds SetTimer(2, 3000, NULL); } // if a label "button" has been clicked, and we just clicked on a bar, then add a label // and reset m_WhichLabel to 0 if (m_WhichLabel > 0) { // get the Series and Point for the label m_chart.GetChartGroups().GetItem(COleVariant(1L)).CoordToDataIndex(X, Y, oc2dFocusX, &Series, &Point, &Distance); labels = m_chart.GetChartLabels(); // determine the text for the label. switch (m_WhichLabel) { case 1: labelText = "One"; break; case 2: labelText = "Two"; break; case 3: labelText = "Three"; break; case 4: labelText = "Four"; break; default: labelText = "!! ERROR !!"; } // loop through all exisiting labels and look if one exists on this bar. for (long i=1; i<=labels.GetCount(); i++) { if (labels.GetItem(COleVariant(i)).GetName() == "Dropped" && labels.GetItem(COleVariant(i)).GetAttachDataIndex().GetSeries() == Series && labels.GetItem(COleVariant(i)).GetAttachDataIndex().GetPoint() == Point) { // set the labels text labels.GetItem(COleVariant(i)).SetIsBatched(true); labels.GetItem(COleVariant(i)).GetText().SetText(labelText); labels.GetItem(COleVariant(i)).SetIsBatched(false); // set that flag so that we don't create a new label needCreate = false; break; } } // Create the new label if necessary if (needCreate) { // add the new label newLabel = m_chart.GetChartLabels().Add(); // batch it for better look newLabel.SetIsBatched(true); // set the name of the label newLabel.SetName("Dropped"); // set the label's text newLabel.GetText().SetText(labelText); // attach the label to the bar newLabel.SetIsConnected(true); newLabel.SetOffset(20); newLabel.SetAttachMethod(oc2dAttachDataIndex); newLabel.GetAttachDataIndex().SetSeries(Series); newLabel.GetAttachDataIndex().SetPoint(Point); // change the font size hFontSize.SetCurrency(12,0); newLabel.GetFont().SetSize(hFontSize); // draw the label newLabel.SetIsBatched(false); } // Remove the hilight switch (m_WhichLabel) { case 1: m_MyLabel1.SetHilight(false); break; case 2: m_MyLabel2.SetHilight(false); break; case 3: m_MyLabel3.SetHilight(false); break; case 4: m_MyLabel4.SetHilight(false); break; } // reset m_WhichLabel to 0 m_WhichLabel = 0; // Allow chart modifications now that the label has been placed m_ChartModify = false; } } void CChartLabelsView::OnLabel1() { m_MyLabel1.SetHilight(); // Turn off Highlight from any other labels. switch (m_WhichLabel) { case 2: m_MyLabel2.SetHilight(false); break; case 3: m_MyLabel3.SetHilight(false); break; case 4: m_MyLabel4.SetHilight(false); break; } // set the m_WhichLabel flag to 1 which signifies that this // "Create label button" has been clicked. m_WhichLabel = 1; // Setting M_ChartModify to true stops the bar from changing value when a label is highlighted! m_ChartModify = true; } void CChartLabelsView::OnLabel2() { m_MyLabel2.SetHilight(); // Turn off Highlight from any other labels. switch (m_WhichLabel) { case 1: m_MyLabel1.SetHilight(false); break; case 3: m_MyLabel3.SetHilight(false); break; case 4: m_MyLabel4.SetHilight(false); break; } // set the m_WhichLabel flag to 1 which signifies that this // "Create label button" has been clicked. m_WhichLabel = 2; // Setting M_ChartModify to true stops the bar from changing value when a label is highlighted! m_ChartModify = true; } void CChartLabelsView::OnLabel3() { // change the font of the clicked label. m_MyLabel3.SetHilight(); // Turn off Highlight from any other labels. switch (m_WhichLabel) { case 1: m_MyLabel1.SetHilight(false); break; case 2: m_MyLabel2.SetHilight(false); break; case 4: m_MyLabel4.SetHilight(false); break; } // set the m_WhichLabel flag to 1 which signifies that this // "Create label button" has been clicked. m_WhichLabel = 3; // Setting M_ChartModify to true stops the bar from changing value when a label is highlighted! m_ChartModify = true; } void CChartLabelsView::OnLabel4() { m_MyLabel4.SetHilight(); // Turn off Highlight from any other labels. switch (m_WhichLabel) { case 1: m_MyLabel1.SetHilight(false); break; case 2: m_MyLabel2.SetHilight(false); break; case 3: m_MyLabel3.SetHilight(false); break; } // set the m_WhichLabel flag to 1 which signifies that this // "Create label button" has been clicked. m_WhichLabel = 4; // Setting M_ChartModify to true stops the bar from changing value when a label is highlighted! m_ChartModify = true; } void CChartLabelsView::OnDestroy() { /* * need to release m_Interior before destroying the Chart via OnDestroy(), * otherwise we have a timing problem, and we are left with a pointer to * something that has been destroyed. */ m_Interior.ReleaseDispatch(); CFormView::OnDestroy(); }