//FILE: CMainWindow.cpp //Implementation of CMainWindow class..... //This file contains code that creates and controls the Main Window //for the CS 460 Image Editor. //include necessary Header Files..... #include //Application Frameworks Header File #include //For predefined dialog box code #include "resource.h" // resource header.... #include "ImgEditjob_ids.h" //contains job id variables #include "MyDialogs.h" // for Dialog Box classes #include "CMainWindow.h" //declarations for CMainWindow class #include "BMPedit24.h" //for access to image editing class #define FALSE 0 #define TRUE 1 #define LINESIZE 8 //for scroll bar calculations, as per MFC textbook // Implementation of class CMainWindow // Begin Message Map... BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT () ON_WM_CREATE () ON_WM_SIZE () ON_WM_HSCROLL () ON_WM_VSCROLL () ON_COMMAND (ID_FILE_OPEN, OnFileOpen) ON_COMMAND (ID_FILE_SAVE, OnFileSave) ON_COMMAND (ID_FILE_SAVE_AS, OnFileSaveAs) ON_COMMAND (ID_FILE_CCLOSE, OnFileClose) ON_COMMAND (ID_APP_EXIT, OnFileExit) ON_COMMAND (ID_EDIT_UNDO, OnEditUndo) ON_COMMAND (ID_EFFECTS_BRIGHTNESS, OnEffectsAdjBrightness) ON_COMMAND (ID_EFFECTS_CONTRAST, OnEffectsAdjContrast) ON_COMMAND (ID_EFFECTS_TINT, OnEffectsAdjTint) ON_COMMAND (ID_EFFECTS_BLACK_AND_WHITE, OnEffectsChToBW) ON_COMMAND (ID_EFFECTS_NEGATIVE, OnEffectsNegative) ON_COMMAND (ID_EFFECTS_ROTATE, OnEffectsRotate) ON_COMMAND (ID_EFFECTS_MIRROR, OnEffectsMirror) ON_COMMAND (ID_ZOOM_ZOOM_IN, OnZoomIn) ON_COMMAND (ID_ZOOM_ZOOM_OUT, OnZoomOut) ON_COMMAND (ID_HELP_ABOUT, OnHelpAbout) END_MESSAGE_MAP () //Member functions for CMainWindow...... CMainWindow::CMainWindow(){ //Create Window with Title Bar Create(NULL, "CS460 Image Editor", //Window Title WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, CRect(300, 100, 900, 700 ), NULL, MAKEINTRESOURCE (IDR_MAINWINDOW)); } CMainWindow::~CMainWindow(){ // Garbage collection.... // delete any dynamically allocated objects here delete image; } int CMainWindow::OnCreate(LPCREATESTRUCT lpcs) { /********************************************************************** This function peforms tasks that must be completed upon creation of the Main Window **********************************************************************/ if(CFrameWnd::OnCreate (lpcs) == -1) return -1; image = new BMPImage; // instantiate an image object // create font for controls... m_controlfont.CreatePointFont (80, _T ("Times New Roman")); // calculate width and height for an average character in the font... CClientDC dc (this); CFont* pOldFont = dc.SelectObject (&m_controlfont); TEXTMETRIC tm; dc.GetTextMetrics (&tm); m_cxchar = tm.tmAveCharWidth; m_cychar = tm.tmHeight + tm.tmExternalLeading; dc.SelectObject (pOldFont); m_nViewWidth = dc.GetDeviceCaps(HORZRES); m_nViewHeight = dc.GetDeviceCaps(VERTRES); return 0; }// OnCreate void CMainWindow::OnSize (UINT nType, int cx, int cy){ /********************************************************************** This handler function peforms calculations necessary for adjusting the size and appearance of the scrollbar whenever the window is resized **********************************************************************/ CFrameWnd::OnSize (nType, cx, cy); // // Set the horizontal scrolling parameters. // int nHScrollMax = 0; m_nHScrollPos = m_nHPageSize = 0; if (cx < m_nViewWidth) { nHScrollMax = m_nViewWidth - 1; m_nHPageSize = cx; m_nHScrollPos = min (m_nHScrollPos, m_nViewWidth - m_nHPageSize - 1); } SCROLLINFO si; si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = nHScrollMax; si.nPos = m_nHScrollPos; si.nPage = m_nHPageSize; SetScrollInfo (SB_HORZ, &si, TRUE); // // Set the vertical scrolling parameters. // int nVScrollMax = 0; m_nVScrollPos = m_nVPageSize = 0; if (cy < m_nViewHeight) { nVScrollMax = m_nViewHeight - 1; m_nVPageSize = cy; m_nVScrollPos = min (m_nVScrollPos, m_nViewHeight - m_nVPageSize - 1); } si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS; si.nMin = 0; si.nMax = nVScrollMax; si.nPos = m_nVScrollPos; si.nPage = m_nVPageSize; SetScrollInfo (SB_VERT, &si, TRUE); } void CMainWindow::OnFileOpen (){ /************************************************************ This function obtains a filename from the predefined CFileDialog dialog box (afxdlgs.h). The function BMPRead is then called to read the bitmap data into a BMPImage object. If there are errors in opening the file, they are handled accordingly here based upon BMPRead's return data. If the file is correctly opened and read, the flag is set to draw the image on the Main Window, and the window is invalidated (redrawn). ************************************************************/ // Create predefined file dialog box CFileDialog FDlgBox (TRUE, _T ("bmp"), _T("*.bmp"), OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, "BITMAP files|*.bmp|"); if (FDlgBox.DoModal () == IDOK) { strcpy(filename, FDlgBox.GetPathName () );// get filename from dialog box data image->saved = 0; // Reset SAVED flag on each open image->altered = 0; // image NOT altered yet.... int file_open_check = image->BMPRead(filename);//read image data from file if ( file_open_check < 0){ // if bad file read, find cause of error.... switch (file_open_check){ case -1: //Error opening file delete image; image = new BMPImage; MessageBox("Cannot open file...", "File Error", MB_OK); break; case -2: //NOT a proper bitmap file.... delete image; image = new BMPImage; MessageBox("File is NOT a bitmap", "File Error", MB_OK); break; case -3: //File is not appropriate type of bitmap delete image; image = new BMPImage; MessageBox("Bitmap is NOT 24-bit RGB. CANNOT process file...", "File Error", MB_OK); break; case -4: //The file is compressed; cannot process delete image; image = new BMPImage; MessageBox("Cannot process compressed data...", "File Error", MB_OK); break; default: break; //If file read is successful, continue } return; //return to await another file } CClientDC xdc (this); //create DC image->temp_dc = new CDC; //assign memory dc to pointer image->temp_dc->CreateCompatibleDC(&xdc); //image->BMPCopy(temp_image); image->EDIT_FUNCTION = JOBID_FILE_OPENED; //Notify OnPaint() of new image file //being opened Invalidate(); //display image in CMainWindow using OnPaint() } } void CMainWindow::OnFileSave (){ /****************************************************************** Save image data to file from which it came ******************************************************************/ image->EDIT_FUNCTION = JOBID_WRITETOFILE; //Set flag to notify OnPaint //to write data to file. Invalidate(FALSE); //cause OnPaint to be called. } void CMainWindow::OnFileSaveAs (){ /************************************************************* ** Saves the currently loaded image under a different filename *************************************************************/ //Create file dialog box --"Save As" CFileDialog FDlgBox (FALSE, _T ("bmp"), _T("*.bmp"), OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, "BITMAP files|*.bmp|"); if (FDlgBox.DoModal () == IDOK) { //Obtain filename from dialog box data strcpy(filename, FDlgBox.GetPathName () ); image->saved = 1; // Mark current file as SAVED //Notify OnPaint() to write data to file image->EDIT_FUNCTION = JOBID_WRITETOFILE; Invalidate(FALSE); //Cause OnPaint() to be called } } void CMainWindow::OnFileClose (){ /****************************************************************** Removes the current BMPImage object, clears the window, and prepares the program to open another image file ******************************************************************/ //If image is altered and NOT saved, inquire user if file is to //be saved.... if((!image->saved && image->altered)) { //Notify the user via a Message Box.... int reply = AfxMessageBox( "Save Changes?", MB_YESNOCANCEL, 0); if (reply == IDYES){ //User wishes to save the file image->EDIT_FUNCTION = JOBID_WRITETOFILE; //Set flag to notify OnPaint() Invalidate(TRUE); //Cause OnPaint() to be executed delete image; //Remove the old image data image = new BMPImage; //Create new object to hold data from next file opened return; } else if(reply == IDNO){ //user does not want to save image to file delete image; //Remove old image data image = new BMPImage; //Create new object to hold data from next file opened Invalidate(TRUE); //Clear the image from the Main Window return; } else if(reply == IDCANCEL){ //user has cancelled the operation return; //No function. Return and wait for next action } } else if (!image->altered) { //If the image has not been altered, just delete it delete image; //Remove the old image data image = new BMPImage; //Create new object to hold data from next file opened Invalidate(TRUE); //Clear the image from the Main Window return; } } void CMainWindow::OnFileExit (){ /****************************************************************** When user wishes to exit the program, OnFileExit() makes sure that the image data is saved if the user wants it to be.... ******************************************************************/ //If the image is altered, but NOT saved, inquire user if file is //to be saved.... if((!image->saved) && image->altered ){ //Inquire via a Message Box int reply = AfxMessageBox( "Save Changes?", MB_YESNOCANCEL, 0); if (reply == IDYES){ //user wishes to save the image to file image->EDIT_FUNCTION = JOBID_WRITETOFILE; //Notify OnPaint of function to //be performed Invalidate(FALSE); //Causes OnPaint() to be executed. PostMessage (WM_CLOSE, 0, 0); //Send a message to CMainWindow, telling it to close } else if(reply == IDNO){ //user does not wish to save the image to a file PostMessage (WM_CLOSE, 0, 0); //Close the main window. } else if(reply == IDCANCEL){ //Action is cancelled. Nothing done. return; //Return to await another menu command. } } PostMessage (WM_CLOSE, 0, 0); //If file is NOT altered, just close the program } void CMainWindow::OnEditUndo (){ /****************************************************************** Undoes ALL previos alterations to the image and restores data to original status by having it redrawn from the original file data ******************************************************************/ image->EDIT_FUNCTION = JOBID_UNDO; //Notify OnPaint() of function to be performed Invalidate(); //Cause OnPaint to be called } void CMainWindow::OnEffectsAdjBrightness (){ /****************************************************************** Creates a modeless dialog box which allows the user to adjust the brightness of the currently displayed image.... ******************************************************************/ //Create modeless dialog box CBrightnessDialog * dlgbox = new CBrightnessDialog; //instantiate new dialog box dlgbox->Create (IDD_BRIGHTNESSCTRL); //Create dialog box based on resource data dlgbox->ShowWindow(SW_SHOW); //Show dialog box } void CMainWindow::OnEffectsAdjContrast (){ /****************************************************************** Creates a modeless dialog box which allows the user to adjust the contrast of the currently displayed image.... ******************************************************************/ //Create modeless dialog box CContrastDialog * dlgbox = new CContrastDialog; //instantiate new dialog box dlgbox->Create (IDD_CONTRASTCTRL); //Create dialog box based on resource data dlgbox->ShowWindow(SW_SHOW); //Show dialog box } void CMainWindow::OnEffectsAdjTint(){ /****************************************************************** Creates a modeless dialog box which allows the user to adjust the red, green and blue tint of the currently displayed image. ******************************************************************/ //Create modeless dialog box CTintDialog * dlgbox = new CTintDialog; //instantiate new dialog box dlgbox->Create (IDD_TINTCTRL); //Create dialog box based on resource data dlgbox->ShowWindow(SW_SHOW); //Show dialog box } void CMainWindow::OnEffectsChToBW (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which changest the image to black-and-white. The window is then invalidated so that OnPaint will call the function to convert the image to black and white. ******************************************************************/ image->EDIT_FUNCTION = JOBID_GRAYSCALE; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. } void CMainWindow::OnEffectsNegative (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which changest the image to its negative The window is then invalidated so that OnPaint will call the function to convert the image to its negative. ******************************************************************/ image->EDIT_FUNCTION = JOBID_NEGATIVE; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. } void CMainWindow::OnEffectsRotate (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which rotates the image 90 degrees to the left. The window is then invalidated so that OnPaint will call the function to perform the rotation..... ******************************************************************/ image->EDIT_FUNCTION = JOBID_ROTATE; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. } void CMainWindow::OnEffectsMirror (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which creates a mirror of the current image. The window is then invalidated so that OnPaint will call the function to perform the reversal. ******************************************************************/ image->EDIT_FUNCTION = JOBID_MIRROR; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. } void CMainWindow::OnZoomIn (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which magnifies the image by 10 percent. The window is then invalidated so that OnPaint will call the function to peform the magnification. ******************************************************************/ image->EDIT_FUNCTION = JOBID_ZOOM_IN; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. Clear window in this case } void CMainWindow::OnZoomOut (){ /****************************************************************** Sets the flag EDIT_FUNCTION (member of class BMPImage) to the appropriate integer that represents the editing feature which reduces the size of theimage by 10 percent. The window is then invalidated so that OnPaint will call the function to peform the reduction. ******************************************************************/ image->EDIT_FUNCTION = JOBID_ZOOM_OUT; //Notify OnPaint() of appropriate function //to call.... Invalidate(FALSE); //cause OnPaint to be called. Clear window in this case } void CMainWindow::OnHelpAbout (){ /****************************************************************** Displays a message box which informs the user about the program and its creator. ******************************************************************/ MessageBox (_T ("CS460 Image Editor Created by Jake Mueller on April 27, 2002"), _T ("About"), NULL|MB_OK); } void CMainWindow::OnPaint (){ /****************************************************************** Called whenever the Main Window receives a repaint command. Code below overloads the function and executes the image editing function indicated by the flag EDIT_FUNCTION(member of BMPImage) ******************************************************************/ //Draw the image in conjunction with a Windows repaint command //Create a Windows Device Context for the Main Window CPaintDC paint_dc (this); //Set Window's origin coordinates based on scrolling positons paint_dc.SetWindowOrg(m_nHScrollPos, m_nVScrollPos); //determine which image editing function must be performed, if any. switch(image->EDIT_FUNCTION){ case (JOBID_FILE_OPENED): //Image file is opened for the first time image->BMPDraw(&paint_dc); ///Draw the image on the Window break; case (JOBID_BRIGHTNESS_UP): //Increase image brightness image->BMPBrightnessUp(&paint_dc); image->altered = TRUE; break; case (JOBID_BRIGHTNESS_DOWN): //Decrease image brightness image->BMPBrightnessDown(&paint_dc); image->altered = TRUE; break; case (JOBID_CONTRAST_UP): //Increse image contrast image->BMPContrastUp(&paint_dc); image->altered = TRUE; break; case (JOBID_CONTRAST_DOWN): //Decrease image contrast image->BMPContrastDown(&paint_dc); image->altered = TRUE; break; case (JOBID_RED_TINT_UP): //Increase strength of red in image image->BMPRedTintUp(&paint_dc); image->altered = TRUE; break; case (JOBID_RED_TINT_DOWN): //Decrease strength of red in image image->BMPRedTintDown(&paint_dc); image->altered = TRUE; break; case (JOBID_GREEN_TINT_UP): //Increase strength of green in image image->BMPGreenTintUp(&paint_dc); image->altered = TRUE; break; case (JOBID_GREEN_TINT_DOWN): //Decrease strength of green in image image->BMPGreenTintDown(&paint_dc); image->altered = TRUE; break; case (JOBID_BLUE_TINT_UP): //Increse strength of blue in image image->BMPBlueTintUp(&paint_dc); image->altered = TRUE; break; case (JOBID_BLUE_TINT_DOWN): //Decrease strength of blue in image image->BMPBlueTintDown(&paint_dc); image->altered = TRUE; break; case (JOBID_GRAYSCALE): //Convert image to black-and-white image->BMPGrayScale(&paint_dc); image->altered = TRUE; break; case (JOBID_NEGATIVE): //Convert image to its negative image->BMPNegative(&paint_dc); image->altered = TRUE; break; case (JOBID_ROTATE): //Rotate image to the left 90 degrees image->BMPRotate90(&paint_dc); image->altered = TRUE; break; case (JOBID_MIRROR): //Mirror the image horizontally image->BMPMirror(&paint_dc); image->altered = TRUE; break; case (JOBID_ZOOM_IN): //Zoom in on image 10% image->BMPZoomIn(&paint_dc); image->altered = TRUE; break; case (JOBID_ZOOM_OUT): //Zoom out on image 10% image->BMPZoomOut(&paint_dc); image->altered = TRUE; break; case (JOBID_UNDO): //Restore image to original image->BMPDraw(&paint_dc); image->altered = FALSE; break; case (JOBID_WRITETOFILE): //data needs to be written to file image->BMPWrite(filename, &paint_dc); break; default: //No image editing function, automatic repaint image->BMPRedraw(&paint_dc); } } void CMainWindow::OnHScroll (UINT nCode, UINT nPos, CScrollBar* pScrollBar){ /***************************************************************************** This function adjusts the view of the Main Window when the scroll bar is moved horizontally. This code has been taken from Programming Windows with MFC Second Editon by Jeff Prosise. *****************************************************************************/ int nDelta; // // Compute the horizontal scroll distance, or "delta." // switch (nCode) { case SB_LINELEFT: nDelta = -LINESIZE; break; case SB_PAGELEFT: nDelta = -m_nHPageSize; break; case SB_THUMBTRACK: nDelta = (int) nPos - m_nHScrollPos; break; case SB_PAGERIGHT: nDelta = m_nHPageSize; break; case SB_LINERIGHT: nDelta = LINESIZE; break; default: // Ignore other scroll bar messages return; } // // Adjust the delta if adding it to the current scroll position would // cause an underrun or overrun. // int nScrollPos = m_nHScrollPos + nDelta; int nMaxPos = m_nViewWidth - m_nHPageSize; if (nScrollPos < 0) nDelta = -m_nHScrollPos; else if (nScrollPos > nMaxPos) nDelta = nMaxPos - m_nHScrollPos; // // Update the scroll position and scroll the window. // if (nDelta != 0) { m_nHScrollPos += nDelta; SetScrollPos (SB_HORZ, m_nHScrollPos, TRUE); ScrollWindow (-nDelta, 0); } } void CMainWindow::OnVScroll (UINT nCode, UINT nPos, CScrollBar* pScrollBar){ /***************************************************************************** This function adjusts the view of the Main Window when the scroll bar is moved vertically. This code has been taken from Programming Windows with MFC Second Editon by Jeff Prosise. *****************************************************************************/ int nDelta; // // Compute the vertical scroll distance, or "delta." // switch (nCode) { case SB_LINEUP: nDelta = -LINESIZE; break; case SB_PAGEUP: nDelta = -m_nVPageSize; break; case SB_THUMBTRACK: nDelta = (int) nPos - m_nVScrollPos; break; case SB_PAGEDOWN: nDelta = m_nVPageSize; break; case SB_LINEDOWN: nDelta = LINESIZE; break; default: // Ignore other scroll bar messages return; } // // Adjust the delta if adding it to the current scroll position would // cause an underrun or overrun. // int nScrollPos = m_nVScrollPos + nDelta; int nMaxPos = m_nViewHeight - m_nVPageSize; if (nScrollPos < 0) nDelta = -m_nVScrollPos; else if (nScrollPos > nMaxPos) nDelta = nMaxPos - m_nVScrollPos; // // Update the scroll position and scroll the window. // if (nDelta != 0) { m_nVScrollPos += nDelta; SetScrollPos (SB_VERT, m_nVScrollPos, TRUE); ScrollWindow (0, -nDelta); } } //declare the application class which executes CMainWindow functions class CImgEdApp : public CWinApp { public: BOOL InitInstance() //override default function { m_pMainWnd = new CMainWindow(); //create window m_pMainWnd->ShowWindow( m_nCmdShow ); //display it m_pMainWnd->UpdateWindow(); // force the refresh return TRUE; } } ImgEdApp; //instantiate application ////////////////CMainWindow.cpp