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


Comments

  • Need help for OnDraw

    Posted by shilsi on 05/25/2005 05:11am

    Hello, I am developing a GUI in VC++ where in I have to show motion of two cars. Because of the Refreshing, everytime when i minimize & then maximize my window, the contents of the window gets erased. I can't draw the whole simulation again since it takes a lot of calculation. Is there any facility in VC++ (I want to use only device contexts to draw) by which I can retain the screen contents.I tried following... 1) CMetafileDC. Here the refreshing becomes very slow. When there is lot of data on the screen and I refresh again & again, my application throws error. Please give me any good solution.

    Reply
  • Great!

    Posted by Legacy on 10/16/2003 12:00am

    Originally posted by: Nik

    This is great work!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds