#ifndef GDIGRAPH_H
#define GDIGRAPH_H
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#ifndef _UNDOMGR_H_
#error gdigraph.h requires undomgr.h to be included first
#endif
#include <map>
class CGUIObject
{
public:
POINT m_pt;
SIZE m_size;
COLORREF m_crColor;
CGUIObject() : m_crColor(RGB(0,0,0)) { m_pt.x = m_pt.y = 100; m_size.cx = m_size.cy = 20; }
CGUIObject(POINT pt) : m_pt(pt), m_crColor(RGB(0,0,0)) { m_size.cx = m_size.cy = 20; }
CGUIObject(POINT pt, SIZE size) : m_pt(pt), m_size(size), m_crColor(RGB(0,0,0)) {}
CGUIObject(POINT pt, SIZE size, COLORREF crColor) : m_pt(pt), m_size(size), m_crColor(crColor) {}
virtual ~CGUIObject() {}
RECT GetRect()
{
RECT rc = { m_pt.x - m_size.cx / 2, m_pt.y - m_size.cy / 2, m_pt.x + m_size.cx / 2, m_pt.y + m_size.cy / 2 };
return rc;
}
void SetColor(COLORREF crColor)
{
m_crColor = crColor;
}
COLORREF GetColor()
{
return m_crColor;
}
void SetSize(SIZE size)
{
m_size = size;
}
SIZE GetSize()
{
return m_size;
}
void MoveTo(POINT pt)
{
m_pt = pt;
}
virtual void Delete() = 0;
virtual void Draw(HDC hDc) = 0;
virtual LPCWSTR Description() = 0;
};
typedef std::map<long, CGUIObject*> GUIObjectMap;
struct DrawFunctor
{
HDC m_dc;
DrawFunctor(HDC dc) : m_dc(dc) {}
void operator()(std::pair<long, CGUIObject*> p)
{
p.second->Draw(m_dc);
}
};
class CGUIBox : public CGUIObject
{
public:
CGUIBox() : CGUIObject() {}
CGUIBox(POINT pt) : CGUIObject(pt) {}
CGUIBox(POINT pt, SIZE size) : CGUIObject(pt, size) {}
CGUIBox(POINT pt, SIZE size, COLORREF crColor) : CGUIObject(pt, size, crColor) {}
virtual ~CGUIBox() {}
void Delete() { delete this; }
virtual void Draw(HDC hDc)
{
CDCHandle dc(hDc);
CBrush brush;
brush.CreateSolidBrush(m_crColor);
RECT rc = GetRect();
dc.FillRect(&rc, brush);
}
virtual LPCWSTR Description()
{
return L"Create box";
}
};
class CGUIEllipse : public CGUIObject
{
public:
CGUIEllipse() : CGUIObject() {}
CGUIEllipse(POINT pt) : CGUIObject(pt) {}
CGUIEllipse(POINT pt, SIZE size) : CGUIObject(pt, size) {}
CGUIEllipse(POINT pt, SIZE size, COLORREF crColor) : CGUIObject(pt, size, crColor) {}
virtual ~CGUIEllipse() {}
void Delete() { delete this; }
virtual void Draw(HDC hDc)
{
CDCHandle dc(hDc);
RECT rc = GetRect();
dc.Ellipse(&rc);
}
virtual LPCWSTR Description()
{
return L"Create ellipse";
}
};
class CGUIRoundRect : public CGUIObject
{
public:
CGUIRoundRect() : CGUIObject() {}
CGUIRoundRect(POINT pt) : CGUIObject(pt) {}
CGUIRoundRect(POINT pt, SIZE size) : CGUIObject(pt, size) {}
CGUIRoundRect(POINT pt, SIZE size, COLORREF crColor) : CGUIObject(pt, size, crColor) {}
virtual ~CGUIRoundRect() {}
void Delete() { delete this; }
virtual void Draw(HDC hDc)
{
CDCHandle dc(hDc);
POINT pt = { m_size.cx / 4, m_size.cy / 4 };
RECT rc = GetRect();
dc.RoundRect(&rc, pt);
}
virtual LPCWSTR Description()
{
return L"Create round rect";
}
};
class GUIContext
{
public:
void static Initialize(GUIObjectMap* pA, GUIObjectMap* pD)
{
pActiveMap = pA;
pDeletedMap = pD;
}
static GUIObjectMap* pActiveMap;
static GUIObjectMap* pDeletedMap;
};
GUIObjectMap* GUIContext::pActiveMap;
GUIObjectMap* GUIContext::pDeletedMap;
//
// Helper funcations
//
HRESULT CreateUndoUnit(long id, IOleUndoUnit** ppUU);
HRESULT CreateRedoUnit(long id, IOleUndoUnit** ppUU);
HRESULT CreateGroupUnit(IOleParentUndoUnit** ppPUU);
//
// Simple undo / redo units
//
class ATL_NO_VTABLE CUndoUnit :
public CComObjectRootEx<CComSingleThreadModel>,
public IOleUndoUnitImpl<CUndoUnit>,
public CComClassID<>
{
public:
CUndoUnit() { }
BEGIN_COM_MAP(CUndoUnit)
COM_INTERFACE_ENTRY(IOleUndoUnit)
END_COM_MAP()
long m_id;
HRESULT IOleUndoUnitImpl_Do(IOleUndoManager* /*pUndoManager*/)
{
GUIObjectMap::iterator iter = GUIContext::pActiveMap->find(m_id);
if ( iter != GUIContext::pActiveMap->end() )
{
GUIContext::pDeletedMap->insert(*iter);
GUIContext::pActiveMap->erase(iter);
return S_OK;
}
// The object map has become corrupt.
return E_ABORT;
}
HRESULT IOleUndoUnitImpl_CreateUndoUnit(IOleUndoUnit** ppUU)
{
HRESULT hr = CreateRedoUnit(m_id, ppUU);
return SUCCEEDED(hr) ? S_OK : E_ABORT;
}
STDMETHOD(GetDescription)(BSTR* pBstr)
{
GUIObjectMap::iterator iter = GUIContext::pActiveMap->find(m_id);
if ( iter != GUIContext::pActiveMap->end() )
{
*pBstr = ::SysAllocString((*iter).second->Description());
return S_OK;
}
return E_FAIL;
}
};
class ATL_NO_VTABLE CRedoUnit :
public CComObjectRootEx<CComSingleThreadModel>,
public IOleUndoUnitImpl<CRedoUnit>,
public CComClassID<>
{
public:
CRedoUnit() { }
BEGIN_COM_MAP(CRedoUnit)
COM_INTERFACE_ENTRY(IOleUndoUnit)
END_COM_MAP()
long m_id;
HRESULT IOleUndoUnitImpl_Do(IOleUndoManager* /*pUndoManager*/)
{
GUIObjectMap::iterator iter = GUIContext::pDeletedMap->find(m_id);
if ( iter != GUIContext::pDeletedMap->end() )
{
GUIContext::pActiveMap->insert(*iter);
GUIContext::pDeletedMap->erase(iter);
return S_OK;
}
// The object map has become corrupt.
return E_ABORT;
}
HRESULT IOleUndoUnitImpl_CreateUndoUnit(IOleUndoUnit** ppUU)
{
HRESULT hr = CreateUndoUnit(m_id, ppUU);
return SUCCEEDED(hr) ? S_OK : E_ABORT;
}
STDMETHOD(GetDescription)(BSTR* pBstr)
{
GUIObjectMap::iterator iter = GUIContext::pDeletedMap->find(m_id);
if ( iter != GUIContext::pDeletedMap->end() )
{
*pBstr = ::SysAllocString((*iter).second->Description());
return S_OK;
}
return E_FAIL;
}
};
//
// A simple parent unit acting as a command on a group
// of GUIObjects, this can be used for both Undo and Redo
//
class ATL_NO_VTABLE CGroupUnit :
public CComObjectRootEx<CComSingleThreadModel>,
public IOleParentUndoUnitImpl<CGroupUnit>,
public CComClassID<>
{
public:
CGroupUnit() { }
BEGIN_COM_MAP(CGroupUnit)
COM_INTERFACE_ENTRY(IOleParentUndoUnit)
COM_INTERFACE_ENTRY(IOleUndoUnit)
END_COM_MAP()
HRESULT IOleParentUndoUnitImpl_CreateParentUndoUnit(IOleParentUndoUnit** ppPUU)
{
HRESULT hr = CreateGroupUnit(ppPUU);
return SUCCEEDED(hr) ? S_OK : E_ABORT;
}
STDMETHOD(GetDescription)(BSTR* pBstr)
{
*pBstr = ::SysAllocString(L"Create group");
return S_OK;
}
};
HRESULT CreateUndoUnit(long id, IOleUndoUnit** ppUU)
{
CComObject<CUndoUnit>* pObj = NULL;
HRESULT hr = pObj->CreateInstance(&pObj);
if (SUCCEEDED(hr))
{
pObj->AddRef();
pObj->m_id = id;
hr = pObj->QueryInterface(ppUU);
pObj->Release();
}
return hr;
}
HRESULT CreateRedoUnit(long id, IOleUndoUnit** ppUU)
{
CComObject<CRedoUnit>* pObj = NULL;
HRESULT hr = pObj->CreateInstance(&pObj);
if (SUCCEEDED(hr))
{
pObj->AddRef();
pObj->m_id = id;
hr = pObj->QueryInterface(ppUU);
pObj->Release();
}
return hr;
}
HRESULT CreateGroupUnit(IOleParentUndoUnit** ppPUU)
{
CComObject<CGroupUnit>* pObj = NULL;
HRESULT hr = pObj->CreateInstance(&pObj);
if (SUCCEEDED(hr))
{
pObj->AddRef();
hr = pObj->QueryInterface(ppPUU);
pObj->Release();
}
return hr;
}
#endif GDIGRAPH_H