Advanced ActiveX Buttons

kSet Button ActiveX

The kSet Button control is designed for developers who want an alternative to the standard Windows command button. It offers everything that the standard button offers plus a whole lot more.

For creation of control the library ATL 3.0 and VC++ 6.0 (SP 3.0) was used.
Control can be in several states: static, hover, push, disabled and to contain the image and text, allows flexibly changing appearance.
kSet Button control don't subclass an existing window.

Properties
Enabled: sets a value that determines if the control can receive user input.
HoverEnabled: permit a hover state
AppearanceStatic: sets a appearance of control for a static state
AppearanceHover: sets a appearance of control for a hover state
AppearancePush: sets a appearance of control for a push state
ShowFocus: manner of display of focus (draws a rectangle, transition in a hover state, nothing)
ShowStateAsFlat: display a condition through change of backcolor if appearance equal flat or border
BorderColor: the border color of the button.
HighlightColor: the color used to display portions of the button that are highlighted
ShadowColor: the color used to display portions of the button that require shadow effects
TextPushColor: foreground color used to display text of the button at a push state
TextHoverColor: foreground color used to display text of the button at a hover state
TextStaticColor: foreground color used to display text of the button at a static state
PictureAlignment: a value that determines the placement of the picture in relation to the caption.
PictureSpacing: a value that determines the spacing to be used between the picture and the caption.
PicturePush: the picture to be displayed on the button at a push state.
PictureHover: the picture to be displayed on the button at a hover state.
PictureStatic: the picture to be displayed on the button at a static state.
PictureDisabled: When the control is disabled, the STATIC picture displayed will automatically be changed to a disabled look. The disabled state can be overridden by setting the PictureDisabled property.
TextPush: a value that determines the text displayed in the button at a push state
TextStatic: a value that determines the text displayed in the button at a static state
TextHover: a value that determines the text displayed in the button at a hover state
FontHover: the font used for the text at a hover state.
FontStatic: the font used for the text at a hover state.
FontPush: the font used for the text at a hover state.

Methods
DoClick: feign pressing the button
AboutBox: displays the about dialog containing the product name and version.

Event
Click: Occurs when the user presses and releases the mouse button.

Implementation
As the control don't subclass an existing window was already mentioned earlier.
All code engaged by display of the button is concentrated in a class _ Render < > which is mixed class. We use at drawing the button simple wrapper classes for GDI handles such as HFONT, HPEN, etc. Directly draws the button an array of functions, the pointers on which are stored in a static array.

[renderbutton.h]
template <class T>
class _Render
{
...
typedef void (_Render::*PTR_FDRAW)(_kDrawDC& dc, RECT& rc);
static PTR_FDRAW& f_table (int appearance, int status)
{
  static PTR_FDRAW& f_table (int appearance, int status)
  {
  //appearance, status
  static PTR_FDRAW table[8][4] = {...};
  ...
  return table[appearance][status];
  }
}
...
};

template <class T>
void _Render<T>::DrawIt(HDC hdc, int state, RECT& rc)
{
PTR_FDRAW ff;

// We choose function depending on a state and appearance of the button
switch (state)
{
case 0:
  ff = f_table(pT->m_AppearanceStatic, state);
      ...
        }
           
        //draws a button   
(this->*ff)(_kDrawDC(hdc), rc);
...
//display the text
DrawState(...);
...
//draws focus rectangle if need
DrawFocusRect(hdc, &rc_focus);
...
//display an image through method IPicture interface
pPic->Render(...);
...
}

We imported function "TrackMouseEvent" from user32.lib for tracking of mouse pointer.

[kbutton.cpp]
void _kButton::DetectTrackMouse()
{
m_pfTrackMouseEvent = (PTRF_TrackMouseEvent)GetProcAddress
(GetModuleHandle(_T("user32")),_T("TrackMouseEvent"));
}

Or at absence (in Windows 95) is traced moving the mouse from second thread through a class _kMouseMoveImpl.

The class _kMouseMoveImpl inherits logic of work with threads from class _ApartmentThread<> and realizes tear-off interface IMouseMove.

[mousemove.h]
class ATL_NO_VTABLE _kMouseMoveImpl :
public _IMouseMove,
public CComTearOffObjectBase<_kButton>,
public _ApartmentThread<_kMouseMoveImpl, _IMouseMove, &IID__IMouseMove>
{
...
}


[kbutton.h]
COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(IID__IMouseMove, _kMouseMoveImpl, m_pUnkMouseMove.p)

[kbutton.cpp]
void _kButton::TrackMouse()
{
if (m_pfTrackMouseEvent)
{
...
}
else
{
CComQIPtr<_IMouseMove> pI(GetControllingUnknown());
pI->_StartThread(100);
}
}


Use of a class as tear-off interface allows saving memory, as the necessity in kMouseMoveImpl arises only at work under Win95. The similar circuit is applied and at animation of pressing the button (for example by a call a method DoClick)

[kButton.cpp]
STDMETHODIMP _kButton::DoClick(VARIANT_BOOL bAnimate)
{
...
CComQIPtr<_IAnimationClick> pI(GetControllingUnknown());
pI->_StartThread(100);
...
}


The class _ApartmentThread encapsulating a work with STA - creation threads, marshals an interface pointer, etc.

[apartmentthread.h]
template <class Derived, class T, const IID* piid>
class _ApartmentThread
{
...
HRESULT _StartThread(int nTimeOut)
{
...
if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(*piid, (T*)pDerived, &m_pStream))) m_hThread = CreateThread(0, 0, &Apartment, (void*)this, 0, &dw);
...
}
...
}


The properties of control are realized with the help of the macros IMPLEMENT_XXX taken from a file atlctr.h
For properties FontXXX h PictureXXX were written macros: IMPLEMENT_PICTURE_PROPERTY h IMPLEMENT_FONT_PROPERTY and mixed classes _HelperPictureProperty<> and _HelperFontProperty<>

The events are realized through dispinterface IkButtonEvents and custom interface IkButtonEvents for C++ containers.

I used for calculation of ShadowColor and HighlightColor the HSL color model realized in a class HSLModel.

[kbutton.h]
void _kButton::Get3DColors (COLORREF clr, COLORREF& clrShadow, COLORREF& clrHighlight)
{
_HSLModel hsl(clr);
_HSLModel _hs1 = hsl;
BYTE lum = hsl.luminance();
hsl.luminance (lum / 3 * 2);
_hs1.luminance (lum + ((240 - lum) / 2));
clrShadow = hsl.rgb();
clrHighlight = _hs1.rgb();
}

For Visual Basic IDE realized ICategorizeProperties interface in a class _ kICategorizeProperiesImpl.

[categorizeproperties.h]
template <class T>
class ATL_NO_VTABLE _kICategorizeProperiesImpl :
public ICategorizeProperties
{
STDMETHOD(MapPropertyToCategory)(DISPID dispid, PROPCAT* ppropcat )
...
STDMETHOD(GetCategoryName)(PROPCAT propcat, LCID lcid, BSTR* pbstrName)
...
}

[kbutton.h]
class ATL_NO_VTABLE _kButton :
...
public _kICategorizeProperiesImpl<_kButton>,
...
{
...
BEGIN_CATEGORY_PROP_NAME_MAP(_kButton)
CATEGORY_PROP_NAME(1, _T("Picture"))
CATEGORY_PROP_NAME(2, _T("Color"))
END_CATEGORY_PROP_NAME_MAP()

BEGIN_PROPERTY_TO_CATEGORY_NAME_MAP (_kButton)
PROPERTY_TO_CATEGORY(dispidTextPush, PROPCAT_Text)
PROPERTY_TO_CATEGORY(dispidPictureDisabled, 1)
...
END_PROPERTY_TO_CATEGORY_MAP()
...
}

Downloads

Download demo project - 45 Kb
Download source - 204 Kb