Click here to Skip to main content
15,897,226 members
Articles / Desktop Programming / MFC

Undo History Popup

Rate me:
Please Sign up or sign in to vote.
4.65/5 (18 votes)
25 Dec 2003CPOL2 min read 61.9K   2.2K   34  
Pop-up control that displays undo/redo history similar to MS Office
// UndoDemoDoc.cpp : implementation of the CUndoDemoDoc class
//

#include "stdafx.h"
#include "UndoDemo.h"
#include "UndoHistoryPopup.h"
#include "UndoDemoDoc.h"
#include "BCMenu.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CUndoDemoDoc

IMPLEMENT_DYNCREATE(CUndoDemoDoc, CDocument)

BEGIN_MESSAGE_MAP(CUndoDemoDoc, CDocument)
	//{{AFX_MSG_MAP(CUndoDemoDoc)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR_ALL, OnUpdateEditClearAll)
	ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)
	ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
	ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
	ON_COMMAND(ID_EDIT_REDO, OnEditRedo)
	ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo)
	ON_COMMAND(ID_DRAW_ELLIPSE, OnDrawEllipse)
	ON_UPDATE_COMMAND_UI(ID_DRAW_ELLIPSE, OnUpdateDrawEllipse)
	ON_COMMAND(ID_DRAW_LINE, OnDrawLine)
	ON_UPDATE_COMMAND_UI(ID_DRAW_LINE, OnUpdateDrawLine)
	ON_COMMAND(ID_DRAW_RECTANGLE, OnDrawRectangle)
	ON_UPDATE_COMMAND_UI(ID_DRAW_RECTANGLE, OnUpdateDrawRectangle)
	ON_COMMAND(ID_DRAW_CANCEL_ALL, OnDrawCancelAll)
	ON_COMMAND(ID_DRAW_COLOR_BLACK, OnDrawColorBlack)
	ON_COMMAND(ID_DRAW_COLOR_BLUE, OnDrawColorBlue)
	ON_COMMAND(ID_DRAW_COLOR_GREEN, OnDrawColorGreen)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_BLACK, OnUpdateDrawColorBlack)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_BLUE, OnUpdateDrawColorBlue)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_GREEN, OnUpdateDrawColorGreen)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_MAGENTA, OnUpdateDrawColorMagenta)
	ON_COMMAND(ID_DRAW_COLOR_MAGENTA, OnDrawColorMagenta)
	ON_COMMAND(ID_DRAW_COLOR_RED, OnDrawColorRed)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_RED, OnUpdateDrawColorRed)
	ON_COMMAND(ID_DRAW_COLOR_YELLOW, OnDrawColorYellow)
	ON_UPDATE_COMMAND_UI(ID_DRAW_COLOR_YELLOW, OnUpdateDrawColorYellow)
	ON_COMMAND(ID_DRAW_AUTO_REPEAT, OnDrawAutoRepeat)
	ON_UPDATE_COMMAND_UI(ID_DRAW_AUTO_REPEAT, OnUpdateDrawAutoRepeat)
	ON_UPDATE_COMMAND_UI(ID_EDIT_XP_STYLE, OnUpdateEditXpStyle)
	ON_COMMAND(ID_EDIT_XP_STYLE, OnEditXpStyle)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CUndoDemoDoc construction/destruction

CUndoDemoDoc::CUndoDemoDoc()
{
	m_DocState = STATE_IDLE;
   m_CurClr = CLR_BLACK;
   m_ptFirst.x = m_ptFirst.y = 0;
   m_bAutoRepeat = TRUE;
}

CUndoDemoDoc::~CUndoDemoDoc()
{
}

BOOL CUndoDemoDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	m_Undo.SaveUndo (m_MiniDB, "New Document");

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CUndoDemoDoc serialization

void CUndoDemoDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/////////////////////////////////////////////////////////////////////////////
// CUndoDemoDoc diagnostics

#ifdef _DEBUG
void CUndoDemoDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CUndoDemoDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CUndoDemoDoc commands

void CUndoDemoDoc::OnUpdateEditClearAll(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable (m_MiniDB.GetSize () > 0);
}

void CUndoDemoDoc::OnEditClearAll() 
{
   if (IDYES==AfxMessageBox ("Delete all drawing objects?", MB_YESNO)){
      CancelAllOperations ();
      m_DocState = STATE_ERASE_ALL;
      FinishCurrentOperation ();
   }	
}

void CUndoDemoDoc::OnEditUndo() {
   PerformUndoRedo (true);
}

void CUndoDemoDoc::OnUpdateEditUndo(CCmdUI* pCmdUI){
	m_Undo.UpdateUndo (pCmdUI);
}

void CUndoDemoDoc::OnEditRedo() {
	PerformUndoRedo (false);
}
void CUndoDemoDoc::OnUpdateEditRedo(CCmdUI* pCmdUI){
   m_Undo.UpdateRedo (pCmdUI);
}

void CUndoDemoDoc::PerformUndoRedo (bool bDoUndo, int NumActions /*= 1*/)
{
   CancelAllOperations ();
   if (bDoUndo){
      m_Undo.Undo (m_MiniDB, NumActions);
   }
   else{
      m_Undo.Redo (m_MiniDB, NumActions);
   }
   UpdateAllViews (NULL);
}

void CUndoDemoDoc::OnDrawEllipse() 
{
   if (m_DocState == STATE_DRAW_ELLIPSE_PT1 || m_DocState == STATE_DRAW_ELLIPSE_PT2){
      CancelAllOperations ();
      return;
   }
   CancelAllOperations ();
   m_DocState = STATE_DRAW_ELLIPSE_PT1;
   UpdateAllViews (NULL);
}

void CUndoDemoDoc::OnUpdateDrawEllipse(CCmdUI* pCmdUI) 
{
   pCmdUI->SetCheck (m_DocState==STATE_DRAW_ELLIPSE_PT1 || m_DocState==STATE_DRAW_ELLIPSE_PT2);
}

void CUndoDemoDoc::OnDrawLine() 
{
   if (m_DocState == STATE_DRAW_LINE_PT1 || m_DocState == STATE_DRAW_LINE_PT2){
      CancelAllOperations ();
      return;
   }
   CancelAllOperations ();
   m_DocState = STATE_DRAW_LINE_PT1;
   UpdateAllViews (NULL);
}

void CUndoDemoDoc::OnUpdateDrawLine(CCmdUI* pCmdUI) 
{
   pCmdUI->SetCheck (m_DocState==STATE_DRAW_LINE_PT1 || m_DocState==STATE_DRAW_LINE_PT2);
}

void CUndoDemoDoc::OnDrawRectangle() 
{
   if (m_DocState == STATE_DRAW_RECTANGLE_PT1 || m_DocState == STATE_DRAW_RECTANGLE_PT2){
      CancelAllOperations ();
      return;
   }
	CancelAllOperations ();
   m_DocState = STATE_DRAW_RECTANGLE_PT1;
   UpdateAllViews (NULL);
}

void CUndoDemoDoc::OnUpdateDrawRectangle(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck (m_DocState==STATE_DRAW_RECTANGLE_PT1 || m_DocState==STATE_DRAW_RECTANGLE_PT2);
}

void CUndoDemoDoc::OnDrawCancelAll() 
{
   CancelAllOperations();
}

void CUndoDemoDoc::CancelAllOperations()
{
   switch (m_DocState)
   {
      case STATE_IDLE:
         break;

      case STATE_DRAW_RECTANGLE_PT1:
      case STATE_DRAW_LINE_PT1:
      case STATE_DRAW_ELLIPSE_PT1:
         break; //nothing was added to DB

      case STATE_DRAW_RECTANGLE_PT2:
      case STATE_DRAW_LINE_PT2:
      case STATE_DRAW_ELLIPSE_PT2:
         ASSERT (m_MiniDB.GetSize ()>0);
         m_MiniDB.RemoveAt (m_MiniDB.GetUpperBound ());
         break;

      case STATE_ERASE_ALL:
         break;

      default:
         ASSERT (FALSE); //unknown state, don't know what to do
         break;
   }

   m_ptFirst.x = m_ptFirst.y = 0;
   m_DocState = STATE_IDLE;
   UpdateAllViews (NULL);
}

void CUndoDemoDoc::FinishCurrentOperation()
{
   CString str;
   eDocState eOldState = m_DocState;
 
   switch (m_DocState)
   {
	   case STATE_IDLE:
         ASSERT(FALSE); //nothing to finish here!
	      break;
	      
	   case STATE_DRAW_RECTANGLE_PT1:
	   case STATE_DRAW_LINE_PT1:
	   case STATE_DRAW_ELLIPSE_PT1:
         ASSERT(FALSE);
	      break; //nothing to finish yet!
	      
	   case STATE_DRAW_RECTANGLE_PT2:
      case STATE_DRAW_LINE_PT2:
      case STATE_DRAW_ELLIPSE_PT2:
         str = "Draw " + m_MiniDB[m_MiniDB.GetUpperBound ()].ObjectInfo();
         m_Undo.SaveUndo (m_MiniDB, str);
         break;
	      
	   case STATE_ERASE_ALL:
         m_MiniDB.RemoveAll ();
         m_Undo.SaveUndo (m_MiniDB, "Erase All");
	      break;
	      
	   default:
	      ASSERT (FALSE); //unknown state, don't know what to do
	      break;
   }

   m_DocState = STATE_IDLE;

   if (m_bAutoRepeat)
   {
	   switch (eOldState)
	   {
		   case STATE_DRAW_RECTANGLE_PT2:
            OnDrawRectangle ();
            break;
	      case STATE_DRAW_LINE_PT2:
            OnDrawLine ();
            break;
	      case STATE_DRAW_ELLIPSE_PT2:
            OnDrawEllipse ();
            break;
	   }
   }
   else
   {
      CancelAllOperations ();
   }
}

void CUndoDemoDoc::SetCurColor (COLORREF clr)
{
   m_CurClr = clr;
   switch (m_DocState)
   {
	   case STATE_DRAW_RECTANGLE_PT2:
	   case STATE_DRAW_LINE_PT2:
	   case STATE_DRAW_ELLIPSE_PT2:
	      ASSERT (m_MiniDB.GetSize ()>0);
	      m_MiniDB[m_MiniDB.GetUpperBound ()].clr = m_CurClr;
         UpdateAllViews (NULL);
	      break;
   }
}

void CUndoDemoDoc::OnDrawColorBlack() { SetCurColor (CLR_BLACK); }
void CUndoDemoDoc::OnDrawColorGreen() { SetCurColor (CLR_GREEN); }
void CUndoDemoDoc::OnDrawColorBlue()  { SetCurColor (CLR_BLUE); }
void CUndoDemoDoc::OnDrawColorMagenta() { SetCurColor (CLR_MAGENTA); }
void CUndoDemoDoc::OnDrawColorRed() { SetCurColor (CLR_RED); }
void CUndoDemoDoc::OnDrawColorYellow() { SetCurColor (CLR_YELLOW); }

void CUndoDemoDoc::OnUpdateDrawColorBlack(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_BLACK); }
void CUndoDemoDoc::OnUpdateDrawColorBlue(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_BLUE); } 
void CUndoDemoDoc::OnUpdateDrawColorGreen(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_GREEN); }
void CUndoDemoDoc::OnUpdateDrawColorMagenta(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_MAGENTA); }
void CUndoDemoDoc::OnUpdateDrawColorRed(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_RED); }
void CUndoDemoDoc::OnUpdateDrawColorYellow(CCmdUI* pCmdUI) { pCmdUI->SetRadio (m_CurClr == CLR_YELLOW); } 

void CUndoDemoDoc::OnDrawAutoRepeat() 
{
	m_bAutoRepeat = !m_bAutoRepeat;
}

void CUndoDemoDoc::OnUpdateDrawAutoRepeat(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck (m_bAutoRepeat);
}

void CUndoDemoDoc::OnUpdateEditXpStyle(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck (CUndoHistoryPopup::m_bDrawXPStyle);
}

void CUndoDemoDoc::OnEditXpStyle() 
{
   CUndoHistoryPopup::m_bDrawXPStyle = !CUndoHistoryPopup::m_bDrawXPStyle;
   if (BCMenu::GetMenuDrawMode() == BCMENU_DRAWMODE_XP){
      BCMenu::SetMenuDrawMode(BCMENU_DRAWMODE_ORIGINAL);
   }
   else{
      BCMenu::SetMenuDrawMode(BCMENU_DRAWMODE_XP);
   }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions