|
|
#ifndef __UNDO_H__
#define __UNDO_H__
// A CBmObjSequence holds the codes for one undo or redo operation.
class CBmObjSequence : public CByteArray { public:
CBmObjSequence(); ~CBmObjSequence();
void Retrieve(BYTE* rgb, int cb); void RetrieveStr(CString& str);
inline void RetrieveByte(BYTE& b) { Retrieve(&b, 1); } inline void RetrieveInt(int& n) { Retrieve((BYTE*)&n , sizeof (int)); } inline void RetrieveLong(long& n) { Retrieve((BYTE*)&n , sizeof (long)); } inline void RetrieveNum(double& num) { Retrieve((BYTE*)&num, sizeof (double)); } inline void RetrievePtr(CBitmapObj*& ptr) { Retrieve((BYTE*)&ptr, sizeof (CBitmapObj*)); } inline void RetrieveRect(CRect& rc) { Retrieve((BYTE*)&rc , sizeof (rc)); } inline void RetrievePoint(CPoint& pt) { Retrieve((BYTE*)&pt , sizeof (pt)); }
void Cleanup(); BOOL IsUseful(CBitmapObj*&, int&); void Apply();
#ifdef _DEBUG
void Dump(); #endif
int m_nCursor; CString m_strDescription; };
class CUndoBmObj : public CBitmapObj { DECLARE_DYNAMIC(CUndoBmObj)
public: CUndoBmObj(); ~CUndoBmObj();
void BeginUndo(const TCHAR* szCmd, BOOL bResetCursor = TRUE); void BeginUndo(const UINT idCmd, BOOL bResetCursor = TRUE); void EndUndo();
inline BOOL CanUndo() const { return m_nRedoSeqs < m_seqs.GetCount(); }
inline BOOL CanRedo() const { return m_nRedoSeqs > 0; }
inline BOOL InUndoRedo() const { return m_bPerformingUndoRedo; }
void GetUndoString(CString& strUndo); void GetRedoString(CString& strRedo);
void DoUndo(); void DoRedo();
void SetMaxLevels(int nLevels); int GetMaxLevels() const;
void OnSetIntProp( CBitmapObj* pChangedSlob, UINT nPropID, UINT nOldVal );
#ifdef _DEBUG
void Dump(); #endif
inline BOOL IsRecording() { return m_nRecording != 0 && m_nPauseLevel == 0; }
inline void Pause() { m_nPauseLevel += 1; }
inline void Resume() { ASSERT(m_nPauseLevel > 0); m_nPauseLevel -= 1; }
enum { // Note correspondence with PRD
opStart, opEnd, opAction, opIntProp, opLongProp, opBoolProp, opDoubleProp, opStrProp, opSlobProp, opRectProp, opPointProp };
UINT Insert(const void* rgb, int cb); UINT InsertStr(const TCHAR* sz);
inline UINT InsertByte(BYTE b) { return Insert(&b, 1); } inline UINT InsertInt(int n) { return Insert((BYTE*)&n, sizeof (int)); } inline UINT InsertLong(long n) { return Insert((BYTE*)&n, sizeof (long)); } inline UINT InsertNum(double num) { return Insert((BYTE*)&num, sizeof (double)); } inline UINT InsertPtr(const void* ptr) { if (ptr != NULL) { ASSERT(((CObject*)ptr)->IsKindOf(RUNTIME_CLASS(CBitmapObj))); ((CBitmapObj*)ptr)->AddDependant(this); } return Insert((BYTE*)&ptr, sizeof (CBitmapObj*)); } inline UINT InsertRect(const CRect& rc) { return Insert((BYTE*)&rc, sizeof (CRect)); } inline UINT InsertPoint(const CPoint& pt) { return Insert((BYTE*)&pt, sizeof (CPoint)); }
void Flush();
void OnInform(CBitmapObj* pChangedSlob, UINT idChange);
void FlushLast();
private:
void Truncate();
int m_nRecording; // BeginUndo() nesting count
int m_nPauseLevel; // Pause() nesting count
int m_cbUndo;
// These ?Last* variables are used to coalesce consecutive changes
// to the same property...
CBitmapObj* m_pLastSlob; int m_nLastPropID;
// Properties...
int m_nMaxLevels;
CObList m_seqs; // pointers to CBmObjSequences
int m_nRedoSeqs; CBmObjSequence* m_pCurSeq;
BOOL m_bPerformingUndoRedo;
friend class CBmObjSequence; };
#pragma pack(1)
class CUndoRecord { public:
BYTE m_op; CBitmapObj* m_pBitmapObj; UINT m_nPropID; };
class CIntUndoRecord : public CUndoRecord { public:
int m_nOldVal; };
class CLongUndoRecord : public CUndoRecord { public:
long m_nOldVal; };
class CDoubleUndoRecord : public CUndoRecord { public:
double m_numOldVal; };
class CRectUndoRecord : public CUndoRecord { public:
CRect m_rectOldVal; };
class CPointUndoRecord : public CUndoRecord { public:
CPoint m_ptOldVal; };
class CBitmapObjUndoRecord : public CUndoRecord { public:
const CBitmapObj* m_pOldVal; };
#pragma pack()
extern CUndoBmObj NEAR theUndo;
#endif // __UNDO_H__
|