#pragma	title("Image Button Control  --  Version 1.0 -- (ImageBtn.C)")
#pragma	subtitle("  Image Button Control DLL - Interface Definitions")

#pragma	info(noext)

#define	INCL_DOS		   /* Include OS/2 DOS Kernal		*/
#define	INCL_GPI		   /* Include OS/2 PM GPI Interface	*/
#define	INCL_WIN		   /* Include OS/2 PM Windows Interface	*/

#include <os2.h>
#include <string.h>

#include <pmcx.h>

#include "imagebtn.h"

/* This	module contains	an example installable control that can	be used	*/
/* within applications where additional	facilities are provided	that	*/
/* are not found within	the default controls of	OS/2 PM.		*/
/*									*/
/* For complete	details	regarding the PM Control Extensions (PMCX)	*/
/* consult the User's Guide.                                            */
/*									*/
/* The DLL is created using the	following command line invocation:	*/
/*									*/
/*     Icc -G3e- -O+ -Rn -W3 -C	ImageBtn.C				*/

/* Filename:   ImageBtn.C						*/

/*  Version:   1.0							*/
/*  Created:   1993-12-21						*/
/*  Revised:   1994-06-26						*/

/* Routines:   BOOL EXPENTRY ImageBtnRegister(HAB hAB);			*/
/*	       BOOL EXPENTRY ImageBtnQuery(PUSERINFO pControlInfo);	*/
/*	       MRESULT EXPENTRY	ImageBtnWndProc(HWND hWnd, ULONG msg,	*/
/*						MPARAM mp1, MPARAM mp2);*/
/*	       MRESULT EXPENTRY	ImageBtnStyles(HWND hWnd, ULONG	msg,	*/
/*					       MPARAM mp1, MPARAM mp2);	*/


/* Copyright ¸ 1989-1994  Prominare Inc.  All Rights Reserved.		*/

/* --------------------------------------------------------------------	*/

/************************************************************************/
/************************************************************************/
/*		       DISCLAIMER OF WARRANTIES.			*/
/************************************************************************/
/************************************************************************/
/*     The following [enclosed]	code is	library	code created by		*/
/*     Prominare Inc.  This library code is  provided to you solely	*/
/*     for the purpose of assisting you	in the development of your	*/
/*     applications.  The code is provided "AS IS", without		*/
/*     warranty	of any kind.  Prominare	Inc. shall not be liable	*/
/*     for any damages arising out of your use of the library code,	*/
/*     even if they have been advised of the possibility of such	*/
/*     damages.								*/
/************************************************************************/
/************************************************************************/
/* --- Button Notification Messages -----------------------------------	*/

#define	IBN_SELECT 0x1000	   /* Button Pressed			*/

#define	IBS_UP	       0x0001UL	   /* Button State:  Up			*/
#define	IBS_DOWN       0x0002UL	   /* Button State:  Down		*/
#define	IBS_DISABLED   0x0004UL	   /* Button State:  Disabled		*/
#define	IBS_CAPTURE    0x1000UL	   /* Button State:  Capture		*/

/* --- Window Information Structures ----------------------------------	*/

typedef	struct _IMGBTN		   /* imgbtn */
   {
   ULONG    id;			   /* ID Value				*/
   RECTL    rcl;		   /* Frame Rectangle			*/
   RECTL    rclSrc;		   /* Source Rectangle			*/
   POINTL   ptlDest;		   /* Destination Point			*/
   HBITMAP  hbm;		   /* Bitmap Handle			*/
   HBITMAP  hbmDown;		   /* Bitmap Handle			*/
   HBITMAP  hbmDisabled;	   /* Bitmap Handle			*/
   POINTL   aptlShadow[12];	   /* Shadow Polyline Array		*/
   HWND	    hwndOwner;		   /* Owner Window Handle		*/
   HWND	    hwndParent;		   /* Parent Window Handle		*/
   ULONG    flState;		   /* Button State			*/
   LONG	    cx;			   /* Bitmap Width			*/
   LONG	    cy;			   /* Bitmap Height			*/
   HPOINTER hptrArrow;		   /* Arrow Pointer			*/
   CHAR	    szText[256];	   /* Button Text			*/
   } IMGBTN ;

typedef	IMGBTN *PIMGBTN;

typedef	struct _IMAGEBUTTON	   /* ibtn */
   {
   ULONG   cb;			   /* Structure	Size			*/
   ULONG   idBitmap;		   /* Bitmap ID				*/
   ULONG   idBitmapDown;	   /* Bitmap ID				*/
   ULONG   idBitmapDisabled;	   /* Bitmap ID				*/
   } IMAGEBUTTON ;

typedef	IMAGEBUTTON *PIMAGEBUTTON;

/* --- Module Prototype	Definitions -----------------------------------	*/

HMODULE	hmod;			   /* DLL Module Handle			*/

static VOID SizeButton(HWND hWnd, LONG x, LONG y, LONG cx, LONG	cy);
BOOL	EXPENTRY ImageBtnInit(HAB hAB);
BOOL	EXPENTRY ImageBtnQuery(PUSERINFO pUserInfo);
MRESULT	EXPENTRY ImageBtnWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
MRESULT	EXPENTRY ImageBtnStyles(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);

#pragma	subtitle("   Image Button Control - DLL Initialization/Termination Procedure")
#pragma	page( )

/* --- _Dll_InitTerm ----------------------------------- [ Public ] ---	*/
/*									*/
/*     This function is	used to	provide	the DLL	initialization and	*/
/*     termination.  The function is called by the C startup code	*/
/*     and allows the control to register itself and provide any	*/
/*     necessary startup.						*/
/*									*/
/*     This function is	designed for IBM C Set/2 Version 1.0 and IBM	*/
/*     C Set++ Version 2.x						*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     ULONG hModule; =	DLL Module Handle				*/
/*     ULONG fl;      =	Startup	/ Termination Flag			*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     _Dll_InitTerm =	0 : Error Return				*/
/*		     =	1 : Successful Startup / Termination		*/
/*									*/
/* --------------------------------------------------------------------	*/

ULONG _System _Dll_InitTerm(ULONG hModule, ULONG fl)

{
		       /* Determine if in startup or termination mode	*/
if ( fl	== 0 )
		       /* DLL being initialized, save the DLL module	*/
		       /* handle to allow the bitmap loading routines	*/
		       /* routines a means of loading the default	*/
		       /* bitmaps when required				*/
   hmod	= hModule;

return(1UL);
}
#pragma	subtitle("   Image Button Control - Control Initialization Function")
#pragma	page ( )

/* --- ImageBtnRegister	-----------------------------------------------	*/
/*									*/
/*     This function is	used to	register the installable control class	*/
/*     with OS/2 Presentation Manager.	The registration must use the	*/
/*     USER_CWINDOWWORDS to reserve memory for the control to allow for	*/
/*     proper usage by Resource	Editor and for use by the control	*/
/*     dialog and window procedures.  The information for the control	*/
/*     containing the style, presentation parameters and control data	*/
/*     is pointed to by	a pointer that can be referenced by the		*/
/*     control's dialog and window procedure as required.  The memory   */
/*     for the structure is allocated and controlled through Resource	*/
/*     Editor.	 The control can reserve more memory for its use	*/
/*     by adding the memory required to	that of	the USER_CWINDOWWORDS	*/
/*     constant.							*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     HAB hAB;	= Application Anchor Block Handle			*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     ImageBtnRegister	=  TRUE	: Class	Registration Successful		*/
/*			= FALSE	: Class	Registration Failed		*/
/*									*/
/* --------------------------------------------------------------------	*/

BOOL EXPENTRY ImageBtnRegister(HAB hAB)

{
		       /* Register the control class with OS/2		*/
		       /* Presentation Manager and return registration	*/
		       /* result					*/

return(WinRegisterClass(hAB, "Image.Button", (PFNWP)ImageBtnWndProc,
			CS_PARENTCLIP |	CS_SYNCPAINT | CS_SIZEREDRAW,
			USER_CWINDOWWORDS));

}
#pragma	subtitle("   Image Button Control - Query Control Information Function")
#pragma	page ( )

/* --- ImageBtnQuery --------------------------------------------------	*/
/*									*/
/*     This function is	used to	return to the caller information	*/
/*     regarding the installable control and its capabilities.	The	*/
/*     function	should return a	true value otherwise Resource		*/
/*     Editor will not register	the control as being usable.		*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     PUSERINFO pUserInfo; = User Information Pointer			*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     ImageBtnQuery =	TRUE : User Information	Being Returned		*/
/*		     = FALSE : No User Information Available		*/
/*									*/
/* --------------------------------------------------------------------	*/

BOOL EXPENTRY ImageBtnQuery(PUSERINFO pUserInfo)

{
POINTL ptl;			   /* Point Holder			*/

		       /* Complete the User Information	structure	*/
		       /* passed to the	function by Resource Editor	*/

		       /* Complete the version and number of control	*/
		       /* types.  In Version 1.00 of CCRS, only	one	*/
		       /* control type is used.				*/
pUserInfo->ulMajor = 3UL;
pUserInfo->ulMinor = 0UL;
		       /* Complete the author and control classname	*/

memcpy(pUserInfo->szAuthor,    "Prominare Inc.", 15);
memcpy(pUserInfo->szClassname, "Image.Button", 13);
memcpy(pUserInfo->szName,      "ImageBtn", 9);

		       /* Complete the default size and	style of the	*/
		       /* first	user control type			*/

ptl.x =	ptl.y =	52L;
WinMapDlgPoints(HWND_DESKTOP, &ptl, 1UL, FALSE);
pUserInfo->utDefined[0].cx	     = ptl.x;
pUserInfo->utDefined[0].cy	     = ptl.y;
pUserInfo->utDefined[0].flStyle	     = WS_VISIBLE;

		       /* Set the maximum amount of text control can	*/
		       /* accept including NULL	termination byte	*/

pUserInfo->utDefined[0].cMaxText     = CCHTEXTMAX;

		       /* Save the style's dialogue ID, type, control   */
		       /* data size and	count of style masks		*/

pUserInfo->utDefined[0].idDlg	     = DLG_CTRLUSER;
pUserInfo->utDefined[0].ulType	     = UTYPE_PRIVATE;
pUserInfo->utDefined[0].flOptions    = PMCXOPT_REFRESH;
pUserInfo->utDefined[0].cCtlData     = sizeof(IMAGEBUTTON);
pUserInfo->utDefined[0].cMasks	     = 4UL;
pUserInfo->utDefined[0].flStyleType  = STYLETYPE_BITFLAGS;
pUserInfo->utDefined[0].stMasks[0].flStyleMask = WS_VISIBLE;
pUserInfo->utDefined[0].stMasks[0].idStyle     = IDS_VISIBLE;
pUserInfo->utDefined[0].stMasks[1].flStyleMask = WS_GROUP;
pUserInfo->utDefined[0].stMasks[1].idStyle     = IDS_GROUP;
pUserInfo->utDefined[0].stMasks[2].flStyleMask = WS_DISABLED;
pUserInfo->utDefined[0].stMasks[2].idStyle     = IDS_DISABLED;
pUserInfo->utDefined[0].stMasks[3].flStyleMask = WS_TABSTOP;
pUserInfo->utDefined[0].stMasks[3].idStyle     = IDS_TABSTOP;

		       /* Save the description of the control		*/

memcpy(pUserInfo->utDefined[0].szDescription, "Image Button", 13);

		       /* Return the success flag back to Resource	*/
		       /* Editor					*/
return(TRUE);
}
#pragma	subtitle("   Image Button Control - Control Sizing Procedure")
#pragma	page( )

/* --- SizeButton -----------------------------------------------------	*/
/*									*/
/*     This function is	used to	calculate various elements of that	*/
/*     make up the button.						*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     HWND  hWnd; = Window Handle					*/
/*     SHORT x;	   = x Starting	Point					*/
/*     SHORT y;	   = y Starting	Point					*/
/*     SHORT cx;   = Button Width					*/
/*     SHORT cy;   = Button Height					*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     Nothing								*/
/*									*/
/* --------------------------------------------------------------------	*/

static VOID SizeButton(HWND hWnd, LONG x, LONG y, LONG cx, LONG	cy)

{
PIMGBTN	pimgbtn;		   /* Image Button Structure Pointer	*/

		       /* Get the address of the private control data	*/
		       /* structure					*/

pimgbtn	= (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Save the bounding rectangle of the control	*/

pimgbtn->rcl.xLeft   = x;
pimgbtn->rcl.yBottom = y;
pimgbtn->rcl.xRight  = x + cx;
pimgbtn->rcl.yTop    = y + cy;

		       /* Calculate the	positions of the beveled	*/
		       /* edges	of the button				*/

pimgbtn->aptlShadow[ 0].x = 1L;
pimgbtn->aptlShadow[ 0].y = 1L;
pimgbtn->aptlShadow[ 1].x = 1L;
pimgbtn->aptlShadow[ 1].y = pimgbtn->rcl.yTop -	1L;
pimgbtn->aptlShadow[ 2].x = pimgbtn->rcl.xRight	- 1L;
pimgbtn->aptlShadow[ 2].y = pimgbtn->rcl.yTop -	1L;
pimgbtn->aptlShadow[ 3].x = pimgbtn->rcl.xRight	- 2L;
pimgbtn->aptlShadow[ 3].y = pimgbtn->rcl.yTop -	2L;
pimgbtn->aptlShadow[ 4].x = 2L;
pimgbtn->aptlShadow[ 4].y = pimgbtn->rcl.yTop -	2L;
pimgbtn->aptlShadow[ 5].x = 2L;
pimgbtn->aptlShadow[ 5].y = 2L;
pimgbtn->aptlShadow[ 6].x = 2L;
pimgbtn->aptlShadow[ 6].y = 1L;
pimgbtn->aptlShadow[ 7].x = pimgbtn->rcl.xRight	- 1;
pimgbtn->aptlShadow[ 7].y = 1L;
pimgbtn->aptlShadow[ 8].x = pimgbtn->rcl.xRight	- 1L;
pimgbtn->aptlShadow[ 8].y = pimgbtn->rcl.yTop -	2L;
pimgbtn->aptlShadow[ 9].x = pimgbtn->rcl.xRight	- 2L;
pimgbtn->aptlShadow[ 9].y = pimgbtn->rcl.yTop -	3L;
pimgbtn->aptlShadow[10].x = pimgbtn->rcl.xRight	- 2L;
pimgbtn->aptlShadow[10].y = 2L;
pimgbtn->aptlShadow[11].x = 2L;
pimgbtn->aptlShadow[11].y = 2L;

		       /* Save the rectangle of	button for the source	*/
		       /* rectangle of the bitmap			*/

pimgbtn->rclSrc	= pimgbtn->rcl;

		       /* Determine if the bitmap image	width is	*/
		       /* smaller than the button width	and if the case	*/
		       /* determine the	best way of centering the image	*/
		       /* horizontally within the button rectangle	*/

if ( (pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft)	< pimgbtn->cx )
   {
   pimgbtn->rclSrc.xRight += (pimgbtn->rclSrc.xLeft = -((pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft - pimgbtn->cx) / 2L +	1L));
   pimgbtn->ptlDest.x =	0L;
   }
else
   pimgbtn->ptlDest.x =	(pimgbtn->rclSrc.xRight	- pimgbtn->rclSrc.xLeft	  - pimgbtn->cx) / 2L +	1L;

		       /* Determine if the bitmap image	height is	*/
		       /* smaller than the button height and if	the	*/
		       /* case determine the best way of centering the	*/
		       /* image	vertically within the button rectangle	*/

if ( (pimgbtn->rcl.yTop	- pimgbtn->rcl.yBottom)	< pimgbtn->cy )
   {
   pimgbtn->rclSrc.yTop	+= (pimgbtn->rclSrc.yBottom = -((pimgbtn->rcl.yTop - pimgbtn->rcl.yBottom - pimgbtn->cx) / 2L +	1L));
   pimgbtn->ptlDest.y =	0L;
   }
else
   pimgbtn->ptlDest.y =	(pimgbtn->rcl.yTop   - pimgbtn->rcl.yBottom - pimgbtn->cy) / 2L	+ 1L;
}
#pragma	subtitle("   Image Button Control - Control Window Procedure")
#pragma	page( )

/* --- ImageBtnWndProc ------------------------------------------------	*/
/*									*/
/*     This function is	used to	process	the messages for the image	*/
/*     button control.							*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     HWND   hWnd; = Window Handle					*/
/*     ULONG  msg;  = PM Message					*/
/*     MPARAM mp1;  = Message Parameter	1				*/
/*     MPARAM mp2;  = Message Parameter	2				*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     ImageBtnWndProc = Message Handling Result			*/
/*									*/
/* --------------------------------------------------------------------	*/

MRESULT	EXPENTRY ImageBtnWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)

{
BITMAPINFOHEADER bmpi;		   /* Bitmap Information Header		*/
HMODULE		 hmodBitmap;	   /* Module Handle			*/
HPS		 hPS;		   /* Presentation Space Handle		*/
PWNDPARAMS	 pwprm;		   /* Window Parameters	Pointer		*/
PCREATESTRUCT	 pcrst;		   /* Create Structure Pointer		*/
PIMAGEBUTTON	 pib;		   /* Image Button Structure Pointer	*/
PIMGBTN		 pimgbtn;	   /* Image Button Structure Pointer	*/
POINTL		 ptl;		   /* Drawing Point			*/
RECTL		 rcl;		   /* Rectangle	Holder			*/
ULONG		 id;		   /* ID Value				*/

switch ( msg )
   {

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	1: Control creation						*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Creation	sequence						*/
   /*********************************************************************/

   case	WM_CREATE :
		       /* Create a private control data	area		*/

       DosAllocMem((PPVOID)(PVOID)&pimgbtn, 4096UL, PAG_READ | PAG_WRITE | PAG_COMMIT);

		       /* Save the address of the text string pointer	*/
		       /* in the control's reserved memory to allow it  */
		       /* to be	referenced as required by the control	*/

       WinSetWindowPtr(hWnd, QWW_CDATA,	(PVOID)pimgbtn);

		       /* Get the control's creation structure address  */
		       /* to copy the default text of the control to	*/
		       /* the memory in	the heap			*/

       pib   =	(PIMAGEBUTTON)PVOIDFROMMP(mp1);
       pcrst = (PCREATESTRUCT)PVOIDFROMMP(mp2);

		       /* Get a	temporary presentation space for the	*/
		       /* window to allow the creation of the bitmaps	*/
		       /* for each of the tools	buttons.		*/
		       /* Load each of the tools image bitmaps from the	*/
		       /* DLL and create a bitmap that will be shown in	*/
		       /* each button					*/

       if ( pib	&& pib->idBitmap )
	   {
	   hmodBitmap =	(HMODULE)NULL;
	   id =	pib->idBitmap;
	   }
       else
	   {
	   hmodBitmap =	hmod;
	   id =	IDB_DEFAULT;
	   }

       if ( !(pimgbtn->hbm = GpiLoadBitmap(hPS = WinGetPS(HWND_DESKTOP), hmodBitmap,
					   id, 0L, 0L))	)
	    pimgbtn->hbm = GpiLoadBitmap(hPS, hmod, IDB_DEFAULT, 0L, 0L);

       GpiQueryBitmapParameters(pimgbtn->hbm, &bmpi);
       pimgbtn->cx = bmpi.cx;
       pimgbtn->cy = bmpi.cy;

       if ( pib	&& pib->idBitmapDown )
	   id =	pib->idBitmapDown;
       else
	   id =	IDB_DEFAULTDOWN;
       if ( !(pimgbtn->hbmDown = GpiLoadBitmap(hPS, hmodBitmap,	id, 0L,	0L)) )
	    pimgbtn->hbmDown = GpiLoadBitmap(hPS, hmod,	IDB_DEFAULTDOWN, 0L, 0L);

       if ( pib	)
	   id =	pib->idBitmapDisabled;
       else
	   id =	IDB_DEFAULTDISABLED;
       if ( !(pimgbtn->hbmDisabled = GpiLoadBitmap(hPS,	hmodBitmap, id,	0L, 0L)) )
	    pimgbtn->hbmDisabled = GpiLoadBitmap(hPS, hmod, IDB_DEFAULTDISABLED, 0L, 0L);

		       /* Release the temporary	presentation space	*/
       WinReleasePS(hPS);

       pimgbtn->hwndOwner  = pcrst->hwndOwner;
       pimgbtn->hwndParent = pcrst->hwndParent;
       pimgbtn->id = pcrst->id;
       pimgbtn->flState	= IBS_UP;
       pimgbtn->hptrArrow = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW,
					       FALSE);
       SizeButton(hWnd,	0, 0, pcrst->cx, pcrst->cy);
       if ( pcrst->pszText )
	   strcpy(pimgbtn->szText, pcrst->pszText);
       WinSetPresParam(hWnd, PP_FONTNAMESIZE, 7L, (PVOID)"8.Helv");
       break;

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	2: Sizing and Placement						*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Control being resized						*/
   /*********************************************************************/

   case	WM_SIZE	:
       WinQueryWindowRect(hWnd,	&rcl);

       SizeButton(hWnd,	rcl.xLeft, rcl.yBottom,	(rcl.xRight - rcl.xLeft),
		  (rcl.yTop   -	rcl.yBottom));
       break;

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	3: Focus/Enable	Management					*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Control being resized						*/
   /*********************************************************************/

   case	WM_ENABLE :
       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

       if ( (BOOL)SHORT1FROMMP(mp1) )
	   pimgbtn->flState &= ~IBS_DISABLED;
       else
	   pimgbtn->flState |= IBS_DISABLED;
       WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
       break;

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	4: Text	Input/Output and Presentation Parameter	Interface	*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Process window parameters setting				*/
   /*********************************************************************/

   case	WM_SETWINDOWPARAMS :

		       /* Get the address for the windows parameters	*/
		       /* structure					*/

       pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);

		       /* Check	to see if the text for the control is	*/
		       /* being	set					*/

       if ( pwprm->fsStatus & WPM_TEXT )
	   {
		       /* Text being set, get the address of the text	*/
		       /* string stored	in the heap			*/

	   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Check	to see if any text is being set		*/

	   if (	pwprm->cchText )

		       /* Check	to make	sure that the text that	is to	*/
		       /* be set is not	greater	than the memory		*/
		       /* allocated					*/

	       if ( pwprm->cchText > 255 )
		   {
		   strncpy(pimgbtn->szText, pwprm->pszText, 255);
		   pimgbtn->szText[255]	= 0;
		   }
	       else
		   strcpy(pimgbtn->szText, pwprm->pszText);
	   else
		       /* No text is being set,	clear any existing text	*/

	       pimgbtn->szText[0] = 0;
	   }
       break;

   /*********************************************************************/
   /*  Process window parameters query					*/
   /*********************************************************************/

   case	WM_QUERYWINDOWPARAMS :

		       /* Get the address for the windows parameters	*/
		       /* structure					*/

       pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);

		       /* Determine the	type of	query			*/

       if ( pwprm->fsStatus & (WPM_TEXT	| WPM_CCHTEXT) )
	   {
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

	   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Copy the text	from the string	to the		*/
		       /* structure					*/

	   strcpy(pwprm->pszText, pimgbtn->szText);

		       /* Place	the length the string within the	*/
		       /* structure					*/

	   pwprm->cchText = (ULONG)strlen(pimgbtn->szText);
	   }
       else
	   if (	pwprm->fsStatus	& WPM_TEXT )
	       {
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

	       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Copy the text	from the string	to the		*/
		       /* structure					*/

	       strcpy(pwprm->pszText, pimgbtn->szText);
	       }
	   else
	       if ( pwprm->fsStatus & WPM_CCHTEXT )
		   {
		       /* Text length being asked for, get the address	*/
		       /* of the text string stored in the heap		*/

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Place	the length the string within the	*/
		       /* structure					*/

		   pwprm->cchText = (ULONG)strlen(pimgbtn->szText);
		   }
	       else
		   return(WinDefWindowProc(hWnd, msg, mp1, mp2));
       break;

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	5: Mouse interface						*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Button 1	Down							*/
   /*********************************************************************/

   case	WM_BUTTON1DOWN :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

       if ( pimgbtn->flState & IBS_DISABLED )
	   return(0L);
       else
	   {
	   pimgbtn->flState = IBS_DOWN | IBS_CAPTURE;

		       /* Set the mouse	capture	to follow the movement	*/
		       /* of the mouse pointer until the mouse button	*/
		       /* is released					*/

	   WinSetCapture(HWND_DESKTOP, hWnd);

	   WinInvalidateRect(hWnd, NULL, TRUE);
	   }
       break;

   /*********************************************************************/
   /*  Button 1	Up							*/
   /*********************************************************************/

   case	WM_BUTTON1UP :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

       if ( pimgbtn->flState & IBS_DISABLED )
	   return(0L);
       else
	   {
	   pimgbtn->flState = IBS_UP;

		       /* Release the mouse capture since the user has	*/
		       /* released the mouse button			*/

	   WinSetCapture(HWND_DESKTOP, (HWND)NULL);

		       /* Post a message to the	main window using the	*/
		       /* command message value	to inform the control	*/
		       /* owner	that the button	has been selected	*/

	   ptl.x = (LONG)SHORT1FROMMP(mp1);
	   ptl.y = (LONG)SHORT2FROMMP(mp1);
	   if (	WinPtInRect((HAB)NULL, &pimgbtn->rcl, &ptl) )
	       {
	       WinPostMsg(pimgbtn->hwndOwner, WM_COMMAND,
			  MPFROMSHORT(pimgbtn->id),
			  MPFROM2SHORT(TRUE, CMDSRC_OTHER));

		       /* Invalidate the button	image to update	it from	*/
		       /* down position					*/

	       WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
	       }
	   }
       break;

   /*********************************************************************/
   /*  Mouse move							*/
   /*********************************************************************/

   case	WM_MOUSEMOVE :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);
       if ( pimgbtn->flState & IBS_CAPTURE )
	   {
	   ptl.x = (LONG)SHORT1FROMMP(mp1);
	   ptl.y = (LONG)SHORT2FROMMP(mp1);
	   if (	!WinPtInRect((HAB)NULL,	&pimgbtn->rcl, &ptl) )
	       {
	       if ( pimgbtn->flState & IBS_DOWN	)
		   {
		   pimgbtn->flState = IBS_UP | IBS_CAPTURE;
		   WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
		   }
	       }
	   else
	       if ( pimgbtn->flState & IBS_UP )
		   {
		   pimgbtn->flState = IBS_DOWN | IBS_CAPTURE;
		   WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
		   }
	   }

       WinSetPointer(HWND_DESKTOP,
		     (HPOINTER)WinSendMsg(pimgbtn->hwndOwner,
					  WM_CONTROLPOINTER,
					  MPFROMSHORT(pimgbtn->id),
					  MPFROMLONG(pimgbtn->hptrArrow)));
       break;

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	6: Keyboard interface						*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Key pressed							*/
   /*********************************************************************/

   case	WM_CHAR	:
		       /* Check	for the	key up flag in which case the	*/
		       /* condition should be ignored			*/

       if ( SHORT1FROMMP(mp1) &	KC_KEYUP )
	   return(0L);
		       /* Check	for virtual keys			*/

       if ( SHORT1FROMMP(mp1) &	KC_VIRTUALKEY )
	   switch ( SHORT2FROMMP(mp2) )
	       {
	       case VK_ENTER :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		   pimgbtn->flState = IBS_DOWN;
		   WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);

		       /* Post a message to the	main window using the	*/
		       /* command message value	to inform the control	*/
		       /* owner	that the button	has been selected	*/

		   WinPostMsg(pimgbtn->hwndOwner, WM_COMMAND,
			      MPFROMSHORT(pimgbtn->id),
			      MPFROM2SHORT(TRUE, CMDSRC_OTHER));

		       /* Invalidate the button	image to update	it from	*/
		       /* down position					*/

		   WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);

		   pimgbtn->flState = IBS_UP;
		   WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
		   WinAlarm(HWND_DESKTOP, WA_NOTE);
		   return(0L);

	       case VK_TAB :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* TAB key pressed, determine which control is	*/
		       /* the next tab stop and	set the	focus on that	*/
		       /* control					*/

		   WinSetFocus(HWND_DESKTOP,
			       WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
					      EDI_NEXTTABITEM));
		   return(0L);

	       case VK_RIGHT :
	       case VK_DOWN :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Right	or down	arrow key pressed, determine	*/
		       /* which	control	is the next entry and set the	*/
		       /* focus	on that	control				*/

		   WinSetFocus(HWND_DESKTOP,
			       WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
					      EDI_NEXTGROUPITEM));
		   return(0L);

	       case VK_BACKTAB :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Shift+TAB key	pressed, determine which	*/
		       /* control is the previous tab stop and set the	*/
		       /* focus	on that	control				*/

		   WinSetFocus(HWND_DESKTOP,
			       WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
					      EDI_PREVTABITEM));
		   return(0L);

	       case VK_LEFT :
	       case VK_UP :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

		   pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Left or up arrow key pressed,	determine	*/
		       /* which	control	is the previous	entry and set	*/
		       /* the focus on that control			*/

		   WinSetFocus(HWND_DESKTOP,
			       WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
					      EDI_PREVGROUPITEM));
		   return(0L);
	       }
		       /* Virtual key not TAB or Shift+TAB, fall	*/
		       /* through to default window procedure		*/

       return(WinDefWindowProc(hWnd, msg, mp1, mp2));

/************************************************************************/
/************************************************************************/
/*									*/
/* Part	7: Control Message interface					*/
/*									*/
/************************************************************************/
/************************************************************************/


/************************************************************************/
/************************************************************************/
/*									*/
/* Part	8: Painting							*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Erase control background						*/
   /*********************************************************************/

   case	WM_ERASEBACKGROUND :
       return(MRFROMLONG(TRUE));

   /*********************************************************************/
   /*  Control painting							*/
   /*********************************************************************/

   case	WM_PAINT :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Get the presentation space for the window	*/
		       /* and draw the grid which the buttons are	*/
		       /* placed					*/

       WinFillRect(hPS = WinBeginPaint(hWnd, (HPS)NULL,	(PRECTL)NULL), &pimgbtn->rcl,
		   SYSCLR_BUTTONMIDDLE);

       ptl = pimgbtn->ptlDest;
       rcl = pimgbtn->rclSrc;

       if ( pimgbtn->flState & IBS_DOWN	)
	   {
	   ptl.x += 2L;
	   if (	(ptl.y -= 2L) <	0L )
	       ptl.y = 0L;
	   if (	pimgbtn->cx > (rcl.xRight - rcl.xLeft) )
	       rcl.xRight -= 2L;

	   if (	pimgbtn->cy > (rcl.yTop	  - rcl.yBottom) )
	       rcl.yBottom += 2L;

	   GpiSetColor(hPS, SYSCLR_BUTTONDARK);
	   }
       else
	   GpiSetColor(hPS, SYSCLR_BUTTONLIGHT);

       WinDrawBitmap(hPS,
		     pimgbtn->flState &	IBS_DISABLED ? pimgbtn->hbmDisabled : pimgbtn->hbm,
		     &rcl, &ptl, 0L, 0L, DBM_IMAGEATTRS);

       GpiMove(hPS, pimgbtn->aptlShadow);
       GpiPolyLine(hPS,	5L, &pimgbtn->aptlShadow[1]);
       if ( (pimgbtn->flState &	IBS_DOWN) != IBS_DOWN )
	   {
	   GpiSetColor(hPS, SYSCLR_BUTTONDARK);
	   GpiMove(hPS,	&pimgbtn->aptlShadow[6]);
	   GpiPolyLine(hPS, 5L,	&pimgbtn->aptlShadow[7]);
	   }

       GpiSetColor(hPS,	SYSCLR_BUTTONDARK);

       ptl.x = 0L;
       ptl.y = 1L;
       GpiMove(hPS, &ptl);
       ptl.y = pimgbtn->rcl.yTop - 1L;
       GpiLine(hPS, &ptl);

       ptl.x = 1L;
       ptl.y = pimgbtn->rcl.yTop;
       GpiMove(hPS, &ptl);
       ptl.x = pimgbtn->rcl.xRight - 1L;
       GpiLine(hPS, &ptl);

       ptl.x = pimgbtn->rcl.xRight;
       ptl.y = pimgbtn->rcl.yTop - 1L;
       GpiMove(hPS, &ptl);
       ptl.y = 1L;
       GpiLine(hPS, &ptl);

       ptl.x = pimgbtn->rcl.xRight - 1L;
       ptl.y = 0L;
       GpiMove(hPS, &ptl);
       ptl.x = 1L;
       GpiLine(hPS, &ptl);

       if ( pimgbtn->szText[0] )
	   {
	   rcl = pimgbtn->rcl;

	   WinDrawText(hPS, -1,	pimgbtn->szText, &rcl, CLR_BLACK, CLR_BACKGROUND,
		       DT_CENTER | DT_BOTTOM | DT_QUERYEXTENT);

	   ptl.x = rcl.xLeft;
	   ptl.y = 4L;
	   if (	pimgbtn->flState & IBS_DOWN )
	       {
	       ptl.x +=	2L;
	       ptl.y -=	2L;
	       }
	   if (	pimgbtn->flState & IBS_DISABLED	)
	       GpiSetPattern(hPS, PATSYM_HALFTONE);
	   else
	       GpiSetPattern(hPS, PATSYM_DEFAULT);
	   GpiSetColor(hPS, CLR_BLACK);
	   GpiCharStringAt(hPS,	&ptl, (LONG)strlen(pimgbtn->szText), pimgbtn->szText);
	   }
		       /* Release the presentation space		*/
       WinEndPaint(hPS);
       break;
/************************************************************************/
/************************************************************************/
/*									*/
/* Part	9: Control being destroyed					*/
/*									*/
/************************************************************************/
/************************************************************************/

   /*********************************************************************/
   /*  Control being destroy, perform necessary	cleanup			*/
   /*********************************************************************/

   case	WM_DESTROY :
		       /* Get the address of the control info from the	*/
		       /* control's reserved memory                     */

       pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QWW_CDATA);

		       /* Delete the bitmap images of the buttons	*/

       GpiDeleteBitmap(pimgbtn->hbm);
       GpiDeleteBitmap(pimgbtn->hbmDown);
       GpiDeleteBitmap(pimgbtn->hbmDisabled);

		       /* Release the heap allocated for use by	the	*/
		       /* control					*/

       DosFreeMem((PVOID)pimgbtn);
       break;
		       /* Default message processing			*/
   default :
       return(WinDefWindowProc(hWnd, msg, mp1, mp2));
   }
return(0L);
}
#pragma	subtitle("   Image Button Control - Control Styles Dialogue Procedure")
#pragma	page ( )

/* --- ImageBtnStyles -------------------------------------------------	*/
/*									*/
/*     This function is	used for the custom control's styles dialogue   */
/*     box procedure.							*/
/*									*/
/*     When the	dialogue is invoked from Resource Editor, the		*/
/*     address of the user style information is	contained in message	*/
/*     parameter 2.  The dialogue is responsible for saving the		*/
/*     address.	 The best method to do this is to save the pointer	*/
/*     in the dialogue's reserved memory where it can be retrieved as   */
/*     needed.								*/
/*									*/
/*     Upon Entry:							*/
/*									*/
/*     HWND   hWnd; = Dialog Window Handle				*/
/*     ULONG  msg;  = PM Message					*/
/*     MPARAM mp1;  = Message Parameter	1				*/
/*     MPARAM mp2;  = Message Parameter	2				*/
/*									*/
/*     Upon Exit:							*/
/*									*/
/*     ImageBtnStyles =	Message	Handling Result				*/
/*									*/
/* --------------------------------------------------------------------	*/

MRESULT	EXPENTRY ImageBtnStyles(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)

{
PUSERSTYLE   pust;		   /* User Style Pointer		*/
PIMAGEBUTTON pib;		   /* Image Button Structure		*/
SWP	     swp;		   /* Screen Window Position Holder	*/

switch ( msg )
   {
		       /* Perform dialogue initialization		*/
   case	WM_INITDLG :
		       /* Save the pointer to user style information	*/
		       /* within the dialog's reserved memory           */

       WinSetWindowPtr(hWnd, QWL_USER, (PVOID)mp2);

		       /* Get the pointer to the user style information	*/

       if ( (pust = (PUSERSTYLE	 )mp2) != NULL )
	   {
		       /* Set the text,	ID symbol and value for	the	*/
		       /* control					*/

	   WinSetDlgItemText(hWnd, EF_TEXT, pust->pszText);
	   pust->pfnSetSymbolID(hWnd, IDBX_SYMBOLVALUE,	pust);
	   pib = (PIMAGEBUTTON)pust->abCtlData;
	   WinSetDlgItemShort(hWnd, EF_DEFAULT,	(USHORT)pib->idBitmap, TRUE);
	   WinSetDlgItemShort(hWnd, EF_DEFAULTDOWN, (USHORT)pib->idBitmapDown, TRUE);
	   WinSetDlgItemShort(hWnd, EF_DEFAULTDISABLED,	(USHORT)pib->idBitmapDisabled, TRUE);

	   if (	pust->flStyle &	WS_VISIBLE )
	       WinSendDlgItemMsg(hWnd, CB_VISIBLE, BM_SETCHECK,
				 MPFROMSHORT(TRUE), 0L);

	   if (	pust->flStyle &	WS_GROUP )
	       WinSendDlgItemMsg(hWnd, CB_GROUP, BM_SETCHECK,
				 MPFROMSHORT(TRUE), 0L);

	   if (	pust->flStyle &	WS_DISABLED )
	       WinSendDlgItemMsg(hWnd, CB_DISABLED, BM_SETCHECK,
				 MPFROMSHORT(TRUE), 0L);

	   if (	pust->flStyle &	WS_TABSTOP )
	       WinSendDlgItemMsg(hWnd, CB_TABSTOP, BM_SETCHECK,
				 MPFROMSHORT(TRUE), 0L);
	   }
		       /* Centre dialog	on the screen			*/

       WinQueryWindowPos(hWnd, (PSWP)&swp);
       WinSetWindowPos(hWnd, HWND_TOP,
		       (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN) - swp.cx) /	2L,
		       (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - swp.cy) /	2L,
		       0L, 0L, SWP_MOVE);
       break;
		       /* Process push button selections		*/
   case	WM_COMMAND :
       switch (	SHORT1FROMMP(mp1) )
	   {
		       /* Enter	pushbutton selected get	the definitions	*/
		       /* for the control				*/
	   case	DID_OK :

		       /* Get the pointer to the user style information	*/

	       if ( (pust = PDATAFROMDLG(hWnd))	!= NULL	)
		   {
		       /* Get the address of the symbol	validation	*/
		       /* function from	the user style information	*/
		       /* structure.  The function will	validate the	*/
		       /* symbol and will check	for duplications of	*/
		       /* values.  A return value of TRUE from the	*/
		       /* validation function indicates	that the symbol	*/
		       /* and value are	acceptable.  Conversely, a	*/
		       /* FALSE	return value indicates that symbol or	*/
		       /* value	was not	acceptable.  In	this case,	*/
		       /* the dialog should not	be exited from and the	*/
		       /* values within	the entry fields should	not be	*/
		       /* saved.					*/

		   if (	!pust->pfnGetSymbolID(hWnd, IDBX_SYMBOLVALUE, pust) )
		       break;
		   else
		       {
		       /* Symbol and value validated, get the text of	*/
		       /* the control and save within the user style	*/
		       /* information structure	for use	by Resource	*/
		       /* Editor					*/

		       pust->cText = WinQueryDlgItemText(hWnd, EF_TEXT,
							 CCHTEXTMAX,
							 pust->pszText);
		       pib = (PIMAGEBUTTON)pust->abCtlData;
		       pib->cb = sizeof(IMAGEBUTTON);
		       WinQueryDlgItemShort(hWnd, EF_DEFAULT,
					    (PSHORT)(PVOID)&pib->idBitmap, TRUE);
		       WinQueryDlgItemShort(hWnd, EF_DEFAULTDOWN,
					    (PSHORT)(PVOID)&pib->idBitmapDown, TRUE);
		       WinQueryDlgItemShort(hWnd, EF_DEFAULTDISABLED,
					    (PSHORT)(PVOID)&pib->idBitmapDisabled, TRUE);

		       pust->flStyle &=	~(WS_VISIBLE | WS_GROUP	| WS_DISABLED |	WS_TABSTOP);
		       if ( WinSendDlgItemMsg(hWnd, CB_VISIBLE,
					      BM_QUERYCHECK, 0L, 0L) )
			   pust->flStyle |= WS_VISIBLE;

		       if ( WinSendDlgItemMsg(hWnd, CB_GROUP,
					      BM_QUERYCHECK, 0L, 0L) )
			   pust->flStyle |= WS_GROUP;

		       if ( WinSendDlgItemMsg(hWnd, CB_DISABLED,
					      BM_QUERYCHECK, 0L, 0L) )
			   pust->flStyle |= WS_DISABLED;

		       if ( WinSendDlgItemMsg(hWnd, CB_TABSTOP,
					      BM_QUERYCHECK, 0L, 0L) )
			   pust->flStyle |= WS_TABSTOP;
		       }
		   }
		       /* Exit the dialogue indicating changes made	*/

	       WinDismissDlg(hWnd, TRUE);
	       break;
		       /* Cancel selected, exit	the dialogue without	*/
		       /* changing anything				*/

	   case	DID_CANCEL :
	       WinDismissDlg(hWnd, FALSE);
	       break;
	   }
       break;
		       /* Close	received, exit dialog			*/
   case	WM_CLOSE :
       WinDismissDlg(hWnd, FALSE);
       break;
		       /* Pass through unhandled messages		*/
   default :
       return(WinDefDlgProc(hWnd, msg, mp1, mp2));
   }
return(0L);

}
