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()
...
}