Microsoft & .NETVisual C#ColorSpace ATL Control

ColorSpace ATL Control


Environment: Written with VC6 and ATL3, tested under NT4 SP3+4+5, Windows95 and 98


This is a follow-up to Rajiv Ramachandran’s excellent Corel PhotoHouse-like Color Chooser (btw: great work, Rajiv!). Rajiv’s Color Chooser is based on MFC dialogs.  My version is based on the ATL and WTL, and is in fact an ActiveX Control.

I’ve used Rajiv’s bitmap and underlying maths code for the graphics itself, and I’ve restricted my control to an RGB and luminosity selector, cutting out the full HSV part of Rajiv’s dialog (mainly to reduce the size of the control).

To use this control, download the demo zip, which contains the built OCX and two built test apps, one built using the MFC, the other with the ATL window and dialog classes.  Then register the control with:   REGSVR32  COLORSPACE.OCX.  The sourcecode zip includes the source for all three projects.

The control is an ATL composite control.  It exposes two properties via four get/put methods: get_RGB, put_RGB, get_HSV and put_HSV; fires one event when the color is changed; and responds to ambient background color changes.  The control does support ErrorInfo, and throws an Error if the user attempts to put an invalid RGB value.  Most of the rest of the code is basically rewritten from Rajiv’s original.

Some interesting ATL bits include:

– The parent class CComCompositeControl<>::OnDraw in atlctl.h has been replaced with a custom one – this is only used for drawing the metafile, and therefore gives the user (the client project developer) a recognisable image of the control while they are working with it in say the dialog editor.

– The parent class CComCompositeControl<>::CalcExtent has been similarly replaced in order to prepare the child control template sizes converted to draw units.

– The use of the undocumented Platform SDK WTL, specifically: atlapp.h for the WTL generically; atlmisc.h for the WTL CString class (very similar to MFC CString); atlgdi.h for CBitmap, CDC, CPen and CBrush; and atlctrls.h for CUpDownCtrl (== CSpinButtonCtrl).  

The primary control class declaration is listed here, to give you an idea of its scope, but for full details see the sourcecode download:


class ATL_NO_VTABLE CColorSpace :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IColorSpace,
&IID_IColorSpace,
&LIBID_COLORSPACESERVERLib>,
public CComCompositeControl<CColorSpace>,
public IPersistStreamInitImpl<CColorSpace>,
public IOleControlImpl<CColorSpace>,
public IOleObjectImpl<CColorSpace>,
public IOleInPlaceActiveObjectImpl<CColorSpace>,
public IViewObjectExImpl<CColorSpace>,
public IOleInPlaceObjectWindowlessImpl<CColorSpace>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CColorSpace>,
public IPersistStorageImpl<CColorSpace>,
public ISpecifyPropertyPagesImpl<CColorSpace>,
public IQuickActivateImpl<CColorSpace>,
public IDataObjectImpl<CColorSpace>,
public IProvideClassInfo2Impl<&CLSID_ColorSpace,
&DIID__IColorSpaceEvents,
&LIBID_COLORSPACESERVERLib>,
public IPropertyNotifySinkCP<CColorSpace>,
public CComCoClass<CColorSpace, &CLSID_ColorSpace>,
public CProxy_IColorSpaceEvents< CColorSpace >
{
public:
CColorSpace();
CColorSpace(COLORREF c);
~CColorSpace();
COLORREF GetColor() { return m_RGB.GetColorref(); }

// overrides
HRESULT OnDraw(ATL_DRAWINFO &di);
BOOL CalcExtent(SIZE& size);

DECLARE_REGISTRY_RESOURCEID(IDR_COLORSPACE)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CColorSpace)
COM_INTERFACE_ENTRY(IColorSpace)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IViewObjectEx)
COM_INTERFACE_ENTRY(IViewObject2)
COM_INTERFACE_ENTRY(IViewObject)
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceObject)
COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY(IOleControl)
COM_INTERFACE_ENTRY(IOleObject)
COM_INTERFACE_ENTRY(IPersistStreamInit)
COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
COM_INTERFACE_ENTRY(IQuickActivate)
COM_INTERFACE_ENTRY(IPersistStorage)
COM_INTERFACE_ENTRY(IDataObject)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()

BEGIN_PROP_MAP(CColorSpace)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
END_PROP_MAP()

BEGIN_CONNECTION_POINT_MAP(CColorSpace)
CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
CONNECTION_POINT_ENTRY(DIID__IColorSpaceEvents)
END_CONNECTION_POINT_MAP()

BEGIN_MSG_MAP(CColorSpace)
CHAIN_MSG_MAP(CComCompositeControl<CColorSpace>)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
COMMAND_HANDLER(IDC_EDIT_BLUE, EN_CHANGE, OnChangeEditBlue)
COMMAND_HANDLER(IDC_EDIT_GREEN, EN_CHANGE, OnChangeEditGreen)
COMMAND_HANDLER(IDC_EDIT_RED, EN_CHANGE, OnChangeEditRed)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
END_MSG_MAP()

BEGIN_SINK_MAP(CColorSpace)
//Make sure the Event Handlers have __stdcall calling convention
END_SINK_MAP()

STDMETHOD(OnAmbientPropertyChange)(DISPID dispid);

// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

// IViewObjectEx
DECLARE_VIEW_STATUS(0)

// IColorSpace
public:
STDMETHOD(get_HSV)(/*[out, retval]*/ LONG *pVal);
STDMETHOD(put_HSV)(/*[in]*/ LONG newVal);
STDMETHOD(get_RGB)(/*[out, retval]*/ OLE_COLOR *pVal);
STDMETHOD(put_RGB)(/*[in]*/ OLE_COLOR newVal);
enum { IDD = IDD_COLORSPACE };

protected:
void DrawFilledColor(CDC *pDC, CRect cr, COLORREF c);
void DrawLines(CDC *pDC);
void DrawXorRect(CDC *pDC, CRect& cr);
void CalcSlopes();
void CalcCuboid();
void DrawMarkers(CDC *pDC);
void SetSpinVals();
void SetEditVals();
void DrawAll();
void DrawRGB(CDC *pDC);
void LoadMappedBitmap(CBitmap& bitmap, UINT nIdResource, CSize& size);

CBitmap m_RGBbitmap;
CDC m_memDC;
int m_nRGBwidth, m_nRGBheight;
RGBType m_RGB;
RGBType m_OldRGB;
CPoint m_ptVertex, m_ptTop, m_ptLeft, m_ptRight;
CRect m_rects[3];
CPoint m_Cuboid[8];
BOOL m_bInMouse;
int m_nIndex;
int m_nRedLen, m_nGreenLen, m_nBlueLen;
LineDesc m_lines[3];
CRect m_rectRGB;
CRect m_rectOldColor, m_rectNewColor;
BOOL m_bInitOver;
BOOL m_bInDrawAll;

HSVType m_HSV;
CRect m_rectBright;
CRect m_rectBrightMark;
CRect m_rectHSV;
CDIB m_BrightDIB;
int m_nMouseIn;
BOOL InBright(CPoint pt);
void TrackPoint(CPoint pt);
void CreateBrightDIB();
void SetDIBPalette();
void CalcRects();
void DrawHSV(CDC *pDC);

// additional rects for drawing the metafile
CRect m_rectRed, m_rectGreen, m_rectBlue;
CRect m_rectSmallControls;
CPoint m_ptRed, m_ptGreen, m_ptBlue, m_ptOld, m_ptNew;

protected:
void UpdateColor(BYTE r, BYTE g, BYTE b);
// Windows message handlers
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnChangeEditBlue(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
LRESULT OnChangeEditGreen(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
LRESULT OnChangeEditRed(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};

For further info on the WTL, see Richard Grimes’s excellent article in Visual C++ Developers Journal Vol3 No3 April 2000, or from http://www.vcdj.com   If you haven’t got the Platform SDK, you can download it (including the WTL and an ATL/WTL AppWizard) from Microsoft’s website: http://msdn.microsoft.com/downloads/c-frame.htm?007#/downloads/sdks/ 

 

Downloads

Download demo project – 113 Kb


Download source – 88 Kb

History

Date Posted: July 22, 2000

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories