Sign in to follow this  
gretty

Supposed to Draw Lines to mouse but doesn't

Recommended Posts

Hello have a graph application that draws a graph onto the client area. It is also supposed to draw 2 lines. One line from the closest x axis value to the mouse & another line from the closest y axis value to the mouse. But these lines are not drawn & I am having an incredibly difficult time figuring out why? Can you help me fix this. I have supplied my code but I think that for someone to help me figure out whats wrong that you will probably need to see every function of my app so I have all my code here( its abit long). So I will list the functions that are responsible for drawing the lines to make it as easy as possible: conGraph.cpp Control Class implementation file - void drawFocus(HDC hdc); - void eraseFocus(HWND hwnd); - bool findInstanceNearest(HWND hwnd, UINT msg, int mouse_x, int mouse_y); conGraph.cpp
#include <windows.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>

#include <stdio.h>
#include <stdlib.h>

#include <stdio.h>
#include <io.h>
#include <fcntl.h>

using namespace std;

#include "conGraph.h"

controller::controller()
{
   // Set default values
   
     m = 2;
     b = -4;
     operand = '+';
     
     xMin = INT_MAX;
     yMin = INT_MAX;
     xMax = INT_MIN;
     yMax = INT_MIN;
     
     xZero      = 20;
     yZero      = 450;
     minCellDim = 10;
     cellWidth  = minCellDim;
     cellHeight = minCellDim;
     precision  = 1;
     xBegin     = -25;
     xEnd       = 5;
     range      = int(xEnd-xBegin);
     xCellNum   = int((xMax-xMin)/precision);
     yCellNum   = int((yMax-yMin)/precision);
     
     // Set default strokes
     xBorder      = CreatePen(PS_SOLID,1,RGB(255,0,0));
     yBorder      = CreatePen(PS_SOLID,1,RGB(255,0,0));
     functionLine = CreatePen(PS_SOLID,2,RGB(0,220,40));
     intervalLine = CreatePen(PS_SOLID,1,RGB(255,255,255));     
     graphRgn     = CreateRectRgn(0,0,1,1);  
     focusRgn     = CreateRectRgn(0,0,1,1);
}

void controller::createGUI(HWND hwnd, HINSTANCE gInstance, UINT controlMsg[])
{
     // Post: Create GUI to alter graph
     
     RECT rRect = {0};
     GetClientRect(hwnd,&rRect);
     HFONT hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
     int dataCB[4] = {43,45,42,47};
     
     int GUIx = 0;
     int GUIy = rRect.bottom-100;
    
     HWND stBorder = CreateWindowEx(0,"Static","",WS_BORDER| WS_CHILD| WS_VISIBLE,//| SS_GRAYRECT,
                                    GUIx,GUIy,rRect.right,100,hwnd,(HMENU)controlMsg[3],gInstance,NULL);
     HWND stfunctionLabel = CreateWindowEx(0,"Static","",WS_BORDER| WS_CHILD| WS_VISIBLE,
                                          GUIx+10,GUIy+15,150,33,hwnd,(HMENU)controlMsg[4],gInstance,NULL);
     HWND styLabel = CreateWindowEx(0,"Static"," y = ",WS_CHILD| WS_VISIBLE,
                                          GUIx+13,GUIy+18,25,20,hwnd,(HMENU)controlMsg[5],gInstance,NULL);
     HWND edMValue = CreateWindowEx(0,"Edit","m",WS_BORDER| WS_CHILD| WS_VISIBLE| ES_NUMBER| ES_CENTER,
                                    GUIx+42,GUIy+15,20,22,hwnd,(HMENU)controlMsg[0],gInstance,NULL);
     HWND stxLabel = CreateWindowEx(0,"Static","x",WS_CHILD| WS_VISIBLE,
                                    GUIx+65,GUIy+18,10,20,hwnd,(HMENU)controlMsg[6],gInstance,NULL);
     HWND cbOperand = CreateWindowEx(0,"Combobox","",WS_BORDER| WS_CHILD| WS_VISIBLE| CBS_DROPDOWNLIST,
                                    GUIx+76,GUIy+15,40,100,hwnd,(HMENU)controlMsg[1],gInstance,NULL);
     HWND edBValue = CreateWindowEx(0,"Edit","b",WS_BORDER| WS_CHILD| WS_VISIBLE| ES_NUMBER| ES_CENTER,
                                    GUIx+116,GUIy+15,20,22,hwnd,(HMENU)controlMsg[2],gInstance,NULL);
     HWND btDrawGrph = CreateWindowEx(0,"Button","Draw Graph",WS_BORDER|WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
                                      rRect.right-87,rRect.bottom-40,80,33,hwnd,(HMENU)controlMsg[7],gInstance,NULL);
     HWND stLimitsLabel = CreateWindowEx(0,"Static","",WS_BORDER|WS_CHILD|WS_VISIBLE,GUIx+10,GUIy+50,150,44,
                                        hwnd,(HMENU)controlMsg[8],gInstance,NULL);
     HWND stXMin = CreateWindowEx(0,"Static","x min=",WS_CHILD|WS_VISIBLE,GUIx+13,GUIy+52,50,20,
                                  hwnd,(HMENU)controlMsg[9],gInstance,NULL);
     HWND edXMin = CreateWindowEx(0,"Edit","0",WS_BORDER|WS_CHILD|WS_VISIBLE|ES_RIGHT,GUIx+48,GUIy+50,30,18,
                                  hwnd,(HMENU)controlMsg[10],gInstance,NULL);
     HWND stRange = CreateWindowEx(0,"Static","Range=",WS_CHILD|WS_VISIBLE,GUIx+83,GUIy+52,50,20,
                                   hwnd,(HMENU)controlMsg[11],gInstance,NULL);
     HWND edRange = CreateWindowEx(0,"Edit","10",WS_BORDER|WS_CHILD|WS_VISIBLE|ES_NUMBER|ES_RIGHT,GUIx+125,GUIy+50,30,18,
                                  hwnd,(HMENU)controlMsg[12],gInstance,NULL);
     HWND stPrec = CreateWindowEx(0,"Static","Precision=",WS_CHILD|WS_VISIBLE,GUIx+72,GUIy+72,50,17,
                                  hwnd,(HMENU)controlMsg[13],gInstance,NULL);
     HWND edPrec = CreateWindowEx(0,"Edit","1",WS_BORDER|WS_CHILD|WS_VISIBLE|ES_NUMBER|ES_RIGHT,GUIx+125,GUIy+70,30,18,
                                  hwnd,(HMENU)controlMsg[14],gInstance,NULL);
     HWND stFocusPnt = CreateWindowEx(0,"Static","X = 0   Y = 0",WS_BORDER|WS_CHILD|WS_VISIBLE|SS_CENTER,
                                      rRect.right-100,GUIy+10,90,45,hwnd,(HMENU)controlMsg[15],gInstance,NULL);
     // Set control fonts
     for(int i=0; i<15; i++) {
         SendDlgItemMessage(hwnd,controlMsg[i],WM_SETFONT,(WPARAM)hfDefault,MAKELPARAM(FALSE,0));
     }     
     // Add operand options to CB cbOperand
     SendDlgItemMessage(hwnd,controlMsg[1],CB_ADDSTRING,0,(LPARAM)" +");
     SendDlgItemMessage(hwnd,controlMsg[1],CB_ADDSTRING,0,(LPARAM)" -");
     SendDlgItemMessage(hwnd,controlMsg[1],CB_ADDSTRING,0,(LPARAM)" *");
     SendDlgItemMessage(hwnd,controlMsg[1],CB_ADDSTRING,0,(LPARAM)" /");
     SendDlgItemMessage(hwnd,controlMsg[1],CB_SETCURSEL,0,0); // select 1st cell of LB
}

void controller::resizeClientArea(HWND hwnd,UINT controlMsgs[])
{
   // Post: Reallign controls when client area is resized
   
   RECT rRect = {0};
   GetClientRect(hwnd,&rRect);    
   int GUIx = 0;
   int GUIy = rRect.bottom-100;
   
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[3]),HWND_TOPMOST,GUIx,GUIy,rRect.right,100,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[4]),HWND_TOPMOST,GUIx+10,GUIy+10,150,33,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[5]),HWND_TOPMOST,GUIx+13,GUIy+18,25,20,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[0]),HWND_TOPMOST,GUIx+42,GUIy+15,20,22,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[6]),HWND_TOPMOST,GUIx+65,GUIy+18,10,20,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[2]),HWND_TOPMOST,GUIx+116,GUIy+15,20,22,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[7]),HWND_TOPMOST,rRect.right-87,rRect.bottom-40,80,33,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[8]),HWND_TOPMOST,GUIx+10,GUIy+47,150,44,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[9]),HWND_TOPMOST,GUIx+13,GUIy+52,50,20,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[10]),HWND_TOPMOST,GUIx+48,GUIy+50,30,18,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[11]),HWND_TOPMOST,GUIx+83,GUIy+52,50,20,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[12]),HWND_TOPMOST,GUIx+125,GUIy+50,30,18,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[13]),HWND_TOPMOST,GUIx+72,GUIy+72,50,17,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[14]),HWND_TOPMOST,GUIx+125,GUIy+70,30,18,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[15]),HWND_TOPMOST,rRect.right-100,GUIy+10,90,45,SWP_NOZORDER);
   SetWindowPos(GetDlgItem(hwnd,controlMsgs[1]),HWND_TOP,GUIx+76,GUIy+15,40,100,SWP_NOZORDER);
   
   precision = 1;  // need to reset precision when window is resized
}

float controller::equation(float xVal)
{
   // Post: Calculate Y value, ie, Determine y = mx(?)b, according to the opperand type/value
   // Maybe rename function to findYValue();
   
   if (operand=='-') {
      return ((m*xVal)-b);
   }
   else if (operand=='*') {
      return ((m*xVal)*b);
   }
   else if (operand=='/') {
      return ((m*xVal)/b);
   }
   else //if (operand=='+')
      return ((m*xVal)+b);                  
}
      
void controller::plotActualGraph()
{
     // Post: Create x,y data points for graph
     //       - xScaled = xZero + (x*cellWidth);
     //       - yScaled = yZero - (y*cellHeight);
     
     functPnt.clear();       // clear vectors 
     xMax = INT_MIN; 
     yMax = INT_MIN;
     xMin = INT_MAX; 
     yMin = INT_MAX;
    
     // Calculate x,y values & store min & max x,y values
     for (float xVal=xBegin; xVal<=xEnd; xVal+=1) { //precision) {
         
         POINT *p = new POINT;
         float yVal = equation(xVal);  // determine y = mx + b
         p->x = (LONG)xVal; p->y = (LONG)yVal;
         functPnt.push_back(p);
         // store min & max values
         if (xVal > xMax) { xMax = xVal; }
         if (yVal > yMax) { yMax = yVal; }
         if (xVal < xMin) { xMin = xVal; }
         if (yVal < yMin) { yMin = yVal; }
     }
     
     if (xMax < 0) {
        xMax = 0;
     }
     if (yMax < 0) {
        yMax = 0;
     }
     range = (xMax-xMin);
}

void controller::plotScaledGraph()
{
     // Pre:  Vector variables x & y MUST have been defined & given values 
     //       & cell dimensions & min/max values calculated
     // Post: Create function line scaled to client area
     
     scaledPnt.clear();  // clear vectors
     
     for (int i=0; i<functPnt.size(); i+=1) { //(int)precision) {
         // scale x,y values for optimal graphical display
         POINT *p = new POINT;
         float xVal = functPnt.at(i)->x;
         float yVal = functPnt.at(i)->y;
         float xTemp = xZero + ((xVal-xMin)*cellWidth);
         float yTemp = yZero - ((yVal-yMin)*cellHeight);
         p->x = (LONG)xTemp; p->y = (LONG)yTemp;
         scaledPnt.push_back(p);
    }
}

void controller::debugGraph()
{
     // Post: Debugging function
     
     cout << "Actual x,y values: \n";
     
     for (int i=0; i<scaledPnt.size(); i++) {
         
         //if (i%10 !=0) { cout << endl; }
         
         cout << functPnt.at(i)->x << "," << functPnt.at(i)->y << " ";
         cout << scaledPnt.at(i)->x << "," << scaledPnt.at(i)->y << "\n";
     }
}

void controller::calculateGraphStats(HWND hwnd)
{
    // Post: Using the user specified precision, xBegin & range we calculate the
    //       optimal cell height & width to fit the graph on screen. In some cases
    //       the range may be too large for the graph to fit on the screen. To solve 
    //       this, the precision will be overwritten & set to a more optimal number.
      
    RECT rRect = {0};
    GetClientRect(hwnd,&rRect);  // get the client area dimensions

    plotActualGraph();           // calculate/plot graph x,y values
    
    // find optimal cell dimensions
    int spaceWidth = (rRect.right-rRect.left)-60;
    int spaceHeight = (rRect.bottom-rRect.top)-140;
    
    xCellNum = int((xMax-xMin)/precision);
    yCellNum = int((yMax-yMin)/precision);
    cellWidth = int(spaceWidth/xCellNum);    
    cellHeight = int(spaceHeight/yCellNum);      
    
    // if range is too large for client width OR height
    while (cellWidth<=minCellDim || cellHeight<=minCellDim) {
        precision += 1;
        xCellNum = int((xMax-xMin)/precision);
        yCellNum = int((yMax-yMin)/precision);
        cellWidth = int(spaceWidth/xCellNum);    
        cellHeight = int(spaceHeight/yCellNum);
    } 
    
    setCentre(hwnd,rRect);  // Find if the graph contains x or y negative values
    plotScaledGraph();      // Plot/fit graph to client area
}

void controller::setCentre(HWND hwnd, RECT hRect)
{
     // Post: Obtain/Calculate the best position for graph within client area 
     //       & set beginning points of x(xXAxis,yXAxis) & y(xYAxis,yYAxis) axis.
     
     // Default x,y axis position |__
     xZero = (hRect.left)+20; 
     yZero = (hRect.bottom)-120;
     xXAxis = xZero;
     yXAxis = yZero;
     xYAxis = xZero;
     yYAxis = yZero;
     
     // if any x or y values are negative then they require x,y borders to be
     // moved
     if (isNegative(functPnt,'x')) { 
         xYAxis += int( abs(cellWidth*(xMin/precision)));
     }
     if (isNegative(functPnt,'y')) {
         yXAxis -= int( abs(cellHeight*(yMin/precision)));            
     }
     
     graphRgn = CreateRectRgn(xXAxis,yYAxis,int(xXAxis+(cellWidth*(xCellNum+0.1))),int(yYAxis-(cellHeight*(yCellNum+0.5)))); 
}

void controller::drawGraph(HDC hdc)
{
     // Pre:  Central client area point(xZero,yZero) must be defined otherwise error
     // Post: Draw graph     
     
     int graphSize = functPnt.size()-1;
     float xBeg,yBeg;
     float xEnd,yEnd;
     drawIntervals(hdc);
     drawBorders(hdc);
     drawText(hdc);
     /*
     for (int i=0; i<graphSize; i++) {
          // Get the lines start point(x,y values)
          xBeg = scaledPnt.at(i)->x;
          ybeg = scaledPnt.at(i)->y;
          // Get the lines end point(x,y values)
          xEnd = scaledPnt.at(i+1)->x;
          yEnd = scaledPnt.at(i+1)->y;
          // Draw line
          drawLine(hdc,(int)xBeg,(int)yBeg,(int)xEnd,(int)yEnd,functionLine);
     }*/
     
     // draw function line from start point to end of graphs range
     drawLine(hdc,int(scaledPnt.at(0)->x),int(scaledPnt.at(0)->y),int(xXAxis+(cellWidth*xCellNum)),int(yYAxis-(cellHeight*yCellNum)),functionLine);
}

void controller::drawBorders(HDC hdc)
{
     // Post: draw x scale & y scale lines/borders  
     drawLine(hdc,xXAxis,yXAxis,int(xXAxis+(cellWidth*(xCellNum+0.1))),yXAxis,xBorder);  // draw x axis
     drawLine(hdc,xYAxis,yYAxis,xYAxis,int(yYAxis-(cellHeight*(yCellNum+0.5))),yBorder); // draw y axis
}

void controller::drawText(HDC hdc)
{
     // Post: Draw intervals labels (1,2,3,5);
     
     int xb = xXAxis-3;
     int yb = yXAxis+5;
     char num[33]; 
     HFONT hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
     SelectObject(hdc,hfDefault);  // select default font
     SetBkMode(hdc,TRANSPARENT); 
     //SetTextColor(hdc,RGB(255,255,255));
     // draw x axis numbers
     for (float i=xMin; i<=xMax; i+=precision) {
         itoa((int)i,num,10);
         TextOut(hdc,xb,yb,(LPCTSTR)num,3);
         xb += (int)cellWidth;
     }
     
     xb = xYAxis-17;
     yb = yYAxis-6;
     // draw y axis numbers
     for (float i=yMin; i<=yMax; i+=precision) {
         itoa((int)i,num,10);
         TextOut(hdc,xb,yb,(LPCTSTR)num,3);
         yb -= (int)cellHeight;
     }
     DeleteObject(hfDefault);  // release dynamic data
}

void controller::drawIntervals(HDC hdc)
{
   // Post: Draws a line/mark at each cell interval along x & y axis   
   
   int x,y;
   
   // draw x axis markers
   for (int i=0, x=(int)xXAxis, y=(int)yXAxis; i<=xCellNum; i++, x+=(int)cellWidth) {
        drawLine(hdc,x,y,x,y+4,intervalLine);
   } 
   // draw y axis markers
   for (int i=0, x=(int)xYAxis, y=(int)yYAxis; i<=yCellNum; i++, y-=(int)cellHeight) {
        drawLine(hdc,x,y,x-4,y,intervalLine);
   } 
}

void controller::drawFocus(HDC hdc)
{
   // Post: - Determine & identify regions above & below function line
   //       - Draw lines from focusPnt to X Axis & focusPnt to the Y Axis
   
   HRGN xLine, yLine;
   POINT xRgn[2];
   POINT yRgn[2];
   
   xRgn[0].x = scaledFocusPnt.x-1; xRgn[0].y = scaledFocusPnt.y+1;
   xRgn[1].x = scaledFocusPnt.x+1; xRgn[1].y = xYAxis;   
   yRgn[0].x = scaledFocusPnt.x-1; yRgn[0].y = scaledFocusPnt.y-1;
   yRgn[1].x = xYAxis; yRgn[1].y = scaledFocusPnt.y+1;
   
   xLine = CreateRectRgn(xRgn[0].x,xRgn[0].y,xRgn[1].x,xRgn[1].y);
   yLine = CreateRectRgn(yRgn[0].x,yRgn[0].y,yRgn[1].x,yRgn[1].y);
   
   CombineRgn(focusRgn,xLine,yLine,RGN_XOR);  
   DeleteObject(xLine);
   DeleteObject(yLine);
   
   // Here I have 2 options to draw the lines, BOTH dont work
   
   // Option 1:
   HBRUSH hb = CreateSolidBrush(RGB(0,220,40));
   FillRgn(hdc,focusRgn,(HBRUSH)hb);
   // Option 2:
   //drawLine(hdc,xRgn[0].x,xRgn[0].y,xRgn[1].x,xRgn[1].y,xBorder); // Custom function that simply draws a line
   //drawLine(hdc,yRgn[0].x,yRgn[0].y,yRgn[1].x,yRgn[1].y,xBorder);
}

void controller::eraseFocus(HWND hwnd)
{
   // Post: Erases focusPnt's lines by invalidating client area
   InvalidateRgn(hwnd,focusRgn,true);   
   //InvalidateRgn(hwnd,xLine,true);
   //InvalidateRgn(hwnd,yLine,true); 
}

bool controller::isNegative(vector<POINT*> v,char axis)
{
   // Post: returns true if vector contains negative values
   
   if (axis=='x') {
      for (int i=0; i<v.size(); i++) {
          POINT *p = v.at(i);
          // if number is negative
          if (p->x < 0) {
             return true;
          }
      }
      return false;      // vector contains no positive values      
   }    
   else if (axis=='y') {
      for (int i=0; i<v.size(); i++) {
          POINT *p = v.at(i);
          if (p->y < 0) {
             return true;
          }
      }
      return false;
   } 
   else return true;  // axis value is invalid
}

void controller::drawLine(HDC hdc,int xBeg,int yBeg, int xEnd, int yEnd, HPEN hPen)
{
     // Post: draw x,y Line & any other required lines
     
     SelectObject(hdc,hPen); // need to add code to check if SelectObject fails
     
     MoveToEx(hdc,xBeg,yBeg,NULL);
     LineTo(hdc,xEnd,yEnd);
}

bool controller::getValues(HWND hwnd, UINT controlMsg[])
{
   // Post: Retrives values from GUI controls to calculate & draw graph

   UINT msgs[] = {controlMsg[0],controlMsg[2],controlMsg[10],controlMsg[12],controlMsg[14]};
   int tempVars[5];
   
   for (int i=0; i<5; i++) {
        BOOL success;
        tempVars[i] = GetDlgItemInt(hwnd,msgs[i],&success,true);
        // if control input is invalid
        if (!success) {
            MessageBox(hwnd,"One or more input fields are blank or invalid. \nValid input includes numerical data & '-' operand.",
                       "Error",MB_OK|MB_ICONERROR);
            return false;
        }  
   }

   getOpperand(hwnd,controlMsg[1]);  // Get operand (+,-,* or /)
   
   // Range cannot be <= 0 
   if (tempVars[3]<=0) {
       tempVars[3] = 1;
   }
   // Precision cannot be <= 0 
   if (tempVars[4]<=0) {
       tempVars[4] = 1;
   }
   
   m         = tempVars[0];
   b         = tempVars[1];
   xBegin    = tempVars[2];
   range     = tempVars[3];
   precision = tempVars[4];
   xEnd      = (xBegin+range);
   return true;
}

void controller::getOpperand(HWND hwnd, UINT msg)
{
   // Post: sets operand according to Combobox selection
   
   int cell = SendDlgItemMessage(hwnd,msg,CB_GETCURSEL,0,0);
   
   switch(cell) {
     
     case 0: operand = '+'; break;
     case 1: operand = '-'; break;
     case 2: operand = '*'; break;
     case 3: operand = '/'; break;
     default: operand = '+'; 
     break;           
   } 
}

bool controller::collisionRect(int mouse_x, int mouse_y)
{
   // Post: Returns true if mouse collides with Graph region(above or below the 
   //       function line) else false
   
   if (PtInRegion(graphRgn,mouse_x,mouse_y) != 0) {
       return true;                                   
   }
   else return false;
}

bool controller::findInstanceNearest(HWND hwnd, UINT msg, int mouse_x, int mouse_y)
{
   // Post: Finds the closest 'function line' point to mouse position &
   //       updates Focus Point(static control text) 
   
   int xDist = INT_MAX;
   int yDist = INT_MAX;
   POINT closestPnt;
   
   // find which axis is closest to mouse pos
   int xAxisDist = abs(yXAxis-mouse_y);
   int yAxisDist = abs(xYAxis-mouse_x);
   
   if (xAxisDist <= yAxisDist) { // if x axis is closest
       for (int i=0; i<scaledPnt.size(); i++) {
           POINT *tempP = scaledPnt.at(i);
           int xTemp = abs(mouse_x-(int)tempP->x);
           int yTemp = abs(mouse_y-(int)tempP->y);
           
           if (xTemp < xDist) {
               xDist = xTemp;
               closestPnt.x = (int)functPnt.at(i)->x;
               closestPnt.y = (int)functPnt.at(i)->y;
           }
       } 
   }
   else { // y axis is closest
       for (int i=0; i<scaledPnt.size(); i++) {
           POINT *tempP = scaledPnt.at(i);
           int xTemp = abs(mouse_x-(int)tempP->x);
           int yTemp = abs(mouse_y-(int)tempP->y);
           
           if (yTemp < yDist) {
               yDist = yTemp;
               closestPnt.x = (int)functPnt.at(i)->x;
               closestPnt.y = (int)functPnt.at(i)->y;
           }
       }  
   }
   
   // if closestPnt == focusPnt
   if ((closestPnt.x != focusPnt.x) && (closestPnt.y != focusPnt.y)) {
      focusPnt = closestPnt;
      scaledFocusPnt.x = LONG(xZero + ((focusPnt.x-xMin)*cellWidth));
      scaledFocusPnt.y = LONG(yZero - ((focusPnt.y-yMin)*cellHeight));
      char buf[MAX_PATH];
      sprintf(buf,"(%i, %i)",focusPnt.x,focusPnt.y);
      SendDlgItemMessage(hwnd,msg,WM_SETTEXT,0,(LPARAM)buf);  // Display closest pnt coords in Static Control
      return true;
   }
   else return false; // no need to redraw focus because focus pnt hasn't changed
}

void controller::garbageCollection()
{
   // Post: Delete all dynamically created variables/objects. Release data
   
   DeleteObject(xBorder);  // delete objects
   DeleteObject(yBorder);
   DeleteObject(functionLine);
   DeleteObject(intervalLine);
   DeleteObject(graphRgn);
   DeleteObject(focusRgn);
   // delete all POINT* objects:
   while (!functPnt.empty()) {         
         delete functPnt.back();
         functPnt.pop_back();
   }
   while (!scaledPnt.empty()) {
         delete scaledPnt.back();
         scaledPnt.pop_back();
   }       
}


winMain.cpp
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>

#include "conGraph.h"

#define IDE_MVALUE    1
#define IDC_OPERAND   2
#define IDE_BVALUE    3
#define IDS_BORDER    4
#define IDS_FUNCTION  5
#define IDS_YLABEL    6
#define IDS_XLABEL    7
#define IDB_DRAWGRAPH 8
#define IDS_BORDER2   9
#define IDS_XMIN      10
#define IDE_XMIN      11
#define IDS_RANGE     12
#define IDE_RANGE     13
#define IDS_PRECISION 14
#define IDE_PRECISION 15
#define IDS_FOCUSPNT  16

const char g_szClassName[] = "myWindowClass";
static HINSTANCE gInstance;
controller graphCon;
bool drawGraph = true;  // do we need to redraw graph
bool drawFocus = false;
UINT controlMsgs[] = {IDE_MVALUE,IDC_OPERAND,IDE_BVALUE,IDS_BORDER,IDS_FUNCTION,IDS_YLABEL,IDS_XLABEL,
                      IDB_DRAWGRAPH,IDS_BORDER2,IDS_XMIN,IDE_XMIN,IDS_RANGE,IDE_RANGE,IDS_PRECISION,
                      IDE_PRECISION,IDS_FOCUSPNT};

// Functions List //
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);


int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = gInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(DKGRAY_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    // if registration of main class fails
    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Graph Application",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 500, 500,
        NULL, NULL, gInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    
    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //HDC hdc;
    switch(msg)
    {
        case WM_CREATE:
               
               graphCon.createGUI(hwnd,gInstance,controlMsgs);
               graphCon.calculateGraphStats(hwnd);
        break;
        case WM_SIZE:
                // Reallign controls & graph when client window is resized
                RECT clientR;
                GetClientRect(hwnd,&clientR);
                // Check that client area is not less than minimum width & height
                if (clientR.right >400 && clientR.bottom >400 ) {
                   graphCon.resizeClientArea(hwnd,controlMsgs);
                   graphCon.calculateGraphStats(hwnd);
                   drawGraph = true;
                   InvalidateRect(hwnd,NULL,true);
                }
                else MessageBox(hwnd,"Graph cannot be drawn when window is less than 400/400 pixels",
                                "Error",MB_OK|MB_ICONERROR);
        break;
        case WM_MOUSEMOVE:
        {
             if (graphCon.collisionRect(LOWORD(lParam),HIWORD(lParam))==true) {
                 // if focusPnt has changed
                 if (graphCon.findInstanceNearest(hwnd,IDS_FOCUSPNT,LOWORD(lParam),HIWORD(lParam)) == true) { // find nearest function line pnt to mouse pos                                                      
                    drawFocus = true;
                    graphCon.eraseFocus(hwnd);
                 }
             }
        }     
        break;
        case WM_COMMAND:
        {
             switch(LOWORD(wParam)) {
                
                case IDB_DRAWGRAPH:
                {    // Draw graph
                     // if all input variables are valid
                     if (graphCon.getValues(hwnd,controlMsgs)==true) {
                         graphCon.calculateGraphStats(hwnd);
                         drawGraph = true;
                         InvalidateRect(hwnd,NULL,true);                          
                     }
                }     
                break;
                default:
                break;                    
             }
        }    
        break;
        case WM_PAINT:
        {
              HDC hdc;
              PAINTSTRUCT ps;
              
              hdc = BeginPaint(hwnd,&ps);
              
              if (drawFocus) {
                  graphCon.drawFocus(hdc);
                  drawFocus = false;           
              }
              if (drawGraph) {
                  graphCon.drawGraph(hdc);
                  drawGraph = false;
              }
              
              EndPaint(hwnd,&ps);
        }
        break;
        case WM_CLOSE:
            graphCon.garbageCollection(); // release dynamic data
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this