/* $Header$ */

//OMNIS Studio CLOCK sample
//contains implementation of sample clock object
/*
Changes
Date			Edit				Bug					Description
22-Jan-21	rmm_svg3								Support for themed fat client SVG icons.
14-Jan-21	rmm_ncs									Removed unnecessary ECM_GETCOMPSTORE... messages.
07-Apr-20	rmm_svg									Added support for SVG images.
29-Apr-19	rmm10067		ST/EC/1552	Issue with digital clock background color.
23-Aug-16	rmm9011									Digital clock was too small on high DPI windows platform.
08-Aug-16	rmm8994			ST/HD/007		Support for high resolution component store external component icons.
23-Nov-10	rmm7000			ST/EM/200		Fixed crash.
08-Oct-08	rmm6473			ST/WT/1367	Fixed crash.
23-Apr-08	rmm_mobile							Mobile device support
24-May-06	rmm5791			ST/EC/1001	24 hour Digital clock showed incorrect time for midnight.
29-Jun-04	rmm5006									Multiple select knobs were missing from quite a few components.
21-Jun-04	rmm4999									Finished rmm4993: remote form fields now show $xxx correctly.
13-Dec-00	rmm3955			ST/WT/293		Drawing issues with clock colours on NT/2000.
12-May-00 PK6020									24hour digital clock
10-Feb-00 MHWEB										Web Version.
01-Oct-98	AE4837			ST/WO/881FC	Tooltips failing (clock was "sucking" WM_TIMER msgs) Fix in V1.3
*/

#include <extcomp.he>
#include <extfval.he>
#include <hwnd.he>
#include <extbmp.he>
#include <gdi.he>
#include "oclock.he"

#include <time.h>
#include <math.h>
#include <string.h>

#define VERSION_MAJOR			1				// Major Version number - Update on MAJOR release builds  
#define VERSION_MINOR			5				// Minor Version number - Update on release builds MHWEB

// MHWEB begins.
#ifdef isWEB
#define LIB_RES_NAME 			1001		/* Resource id of library name */
#define CLOCK_ID 					2001		/* Resource id of control within library */
#else
#define LIB_RES_NAME 			1000		/* Resource id of library name */
#define CLOCK_ID 					2000		/* Resource id of control within library */
#endif
// MHWEB ends.


#define COMPONENT_COUNT 1				/* Number of controls within library */
#define CLOCK_ICON 		1				/* Resource bitmap id */

const qshort
				cClock_FaceColor 					= 1,
				cClock_ShowFace   				= 2,
				cClock_PointsColor   			= 3,
				cClock_ShowSeconds   			= 4,
				cClock_SecondsColor   		= 5,
				cClock_ShowMinutes   			= 6,
				cClock_MinutesColor   		= 7,
				cClock_ShowHours   				= 8,
				cClock_HoursColor   			= 9,
				cClock_ShowIconFace   		= 10,
				cClock_ScaleIconFace   		= 11,
				cClock_IconId   					= 12,
				cClock_Seconds   					= 13,
				cClock_Minutes   					= 14,
				cClock_Hours	   					= 15,
				cClock_TimeZoneAdjust			= 16,
				cClock_TimeZone  					= 17,
				cClock_IsPM  							= 18,
				cClock_Digital						= 19,
				cClock_DigitalColor				= 20,
				cClock_24Hour							= 21,		// PK6020
				// -----------------------
				cRedClock									= 1,
				// -----------------------
       	cClockEvSecs							= 1,
       	cClockEvMin								= 2,
       	cClockEvHours							= 3;

ECOparam CLOCKparams[3] =
{
	6000, fftInteger, 0, 0,			// secs
	6001, fftInteger, 0, 0,      // mins
	6002, fftInteger, 0, 0      // hours
};

ECOmethodEvent CLOCKevents[3] = 
{
	cClockEvSecs,  	5000, 0, 1, &CLOCKparams[0], 0, 0,
	cClockEvMin,  	5001, 0, 1, &CLOCKparams[1], 0, 0,
	cClockEvHours,  5002, 0, 1, &CLOCKparams[2], 0, 0
};

ECOproperty CLOCKproperties[21] =		// PK6020
{ 
	cClock_FaceColor, 		4000, fftInteger, EXTD_FLAG_PWINDCOL, 0, 0, 0,				// face color
	cClock_ShowFace, 			4001, fftBoolean, 0, 0, 0, 0,													// show face
	cClock_PointsColor, 	4002, fftInteger, EXTD_FLAG_PWINDCOL, 0, 0, 0,				// points color
	cClock_ShowSeconds, 	4003, fftBoolean, 0, 0, 0, 0,													// show second
	cClock_SecondsColor, 	4004, fftInteger, EXTD_FLAG_PWINDCOL, 0, 0, 0,				// seconds color
	cClock_ShowMinutes, 	4005, fftBoolean, 0, 0, 0, 0,													// show minutes
	cClock_MinutesColor, 	4006, fftInteger, EXTD_FLAG_PWINDCOL, 0, 0, 0,				// minutes color
	cClock_ShowHours, 		4007, fftBoolean, 0, 0, 0, 0,													// show hours
	cClock_HoursColor, 		4008, fftInteger, EXTD_FLAG_PWINDCOL, 0, 0, 0,				// hours color
	cClock_ShowIconFace, 	4009, fftBoolean, 0, 0, 0, 0,													// iconface
	cClock_ScaleIconFace, 4010, fftBoolean, 0, 0, 0, 0,													// scaleface
	cClock_IconId, 				4011, fftCharacter,EXTD_FLAG_PWINDICON, EXTD_EFLAG_SVG, 0, 0,				// iconid // rmm_svg
	cClock_Seconds,       4012, fftInteger, 0, 0, 0, 0,													// minutes
	cClock_Minutes,				4013, fftInteger, 0, 0, 0, 0,													// seconds
	cClock_Hours,					4014, fftInteger, 0, 0, 0, 0,													// hours
	cClock_TimeZoneAdjust,4015, fftBoolean, 0, 0, 0, 0,													
	cClock_TimeZone,			4016, fftInteger, EXTD_FLAG_EXTCONSTANT,0,7000, 7024,
	cClock_IsPM,          4017, fftBoolean, 0, 0, 0, 0,													
	cClock_Digital,       4018, fftBoolean, 0, 0, 0, 0,													
	cClock_DigitalColor,  4019, fftInteger, EXTD_FLAG_EXTCONSTANT,0,7025, 7027,
	cClock_24Hour,				4020, fftBoolean, 0, 0, 0, 0,													// PK6020
};


tqfClock::tqfClock( HWND pFieldHWnd )
{
	mHWnd = pFieldHWnd;
	mInSendEvent = qfalse;
	
	qlong style = WNDgetWindowLong( mHWnd, GWL_EXSTYLE );
	style |= WND_REDRAWONSIZE;
	WNDsetWindowLong( mHWnd, GWL_EXSTYLE, style );
	
	mShowMins = mShowHours = mShowSecs = mShowFace = qtrue;
	mSecondHandColor = GDI_COLOR_QDKBLUE;
	mMinuteHandColor = GDI_COLOR_QRED;
	mHourHandColor = GDI_COLOR_QDKRED;
	mFacePointsColor = GDI_COLOR_QDKCYAN;
	mFaceColor = GDI_COLOR_QBLACK; 
	mIconID.setEmpty(fftInteger, 0); // rmm_svg
	mScaleFace = qfalse;
	mIconFace = qfalse;  
	mAdjustByTimeZone = qfalse;
	mTimeZone = 12;  
	mIsPM = qfalse; 
	m24Hour = qfalse;		// PK6020
	mIsDigital = qfalse;
	mDigiColor = cRedClock;
	mDigiBitmap = NULL;
	loadDigiClock();
}

tqfClock::~tqfClock()
{
	if ( mDigiBitmap ) GDIdeleteBitmap( mDigiBitmap );
}

qrect tqfClock::getDigitRect( qshort pNum )
{   
	qrect r; r.left = r.top = 0; r.bottom = 31; r.right = 15;
	if ( pNum>=0 && pNum<=9 ) 
		GDIoffsetRect( &r, pNum*16, 0 );
	return r;
}

void tqfClock::loadDigiClock()
{   
	if ( mDigiBitmap ) GDIdeleteBitmap( mDigiBitmap );
	// Start rmm10067
	EXTfldval fval;
	RESloadPNG(gInstLib, mDigiColor + 9, fval); 
	qHandle han = fval.getHandle(qfalse);
	HPIXMAP pmap = GDIHPIXMAPfromSharedPicture(han->mData, han->mDataLen);
	mDigiBitmap = GDIalphaPixmapToBitmap(pmap);
	GDIdeleteHPIXMAP(pmap);
	// End rmm10067
}

qlong tqfClock::attributeSupport( LPARAM pMessage, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci )
{
	switch( pMessage )
	{ 
		case ECM_PROPERTYCANASSIGN: 
		{
			qlong property = (qlong)eci->mParamFirst->mId;
			if ( property==cClock_Seconds || property==cClock_Minutes || property==cClock_Hours || property==cClock_IsPM ) return 0L;
			else return 1L;
		}
		case ECM_SETPROPERTY: 
		{       
			qlong property = ECOgetId(eci);			
			EXTParamInfo* param = ECOfindParamNum( eci, 1 );
			if ( param )
			{
				EXTfldval fval( (qfldval)param->mData );
				switch( property )
				{
					case cClock_FaceColor: 			mFaceColor = (qcol)fval.getLong(); break; 			// face color
					case cClock_ShowFace: 			mShowFace = (qbool)fval.getLong(); break; 			// show face
					case cClock_PointsColor: 		mFacePointsColor = (qcol)fval.getLong(); break; // points color
					case cClock_ShowSeconds: 		mShowSecs = (qbool)fval.getLong(); break; 			// show second
					case cClock_SecondsColor: 	mSecondHandColor = (qcol)fval.getLong(); break; // seconds color
					case cClock_ShowMinutes: 		mShowMins = (qbool)fval.getLong(); break; 			// show minutes
					case cClock_MinutesColor: 	mMinuteHandColor = (qcol)fval.getLong(); break; // minutes color
					case cClock_ShowHours: 			mShowHours = (qbool)fval.getLong(); break; 			// show hours
					case cClock_HoursColor: 		mHourHandColor = (qcol)fval.getLong(); break; 	// hours color
					case cClock_ShowIconFace:		mIconFace = (qbool)fval.getLong(); break; 			// show icon face  
					case cClock_ScaleIconFace:  mScaleFace = (qbool)fval.getLong(); break; 			// scale icon face  
					case cClock_IconId:					mIconID = fval; break; 													// icon face icon id // rmm_svg
					case cClock_TimeZoneAdjust: mAdjustByTimeZone = (qbool)fval.getLong(); break;
					case cClock_TimeZone: 			mTimeZone = (qshort)fval.getLong(); break;
					case cClock_Digital:				mIsDigital = (qbool)fval.getLong(); break;
					case cClock_DigitalColor:		
					{
						mDigiColor = (qshort)fval.getLong(); 
						loadDigiClock();
						break;
					}
					case cClock_24Hour: 				m24Hour = (qbool)fval.getLong(); break;		// PK6020
				}       
				if ( ECOisSetup( mHWnd ) ) 
					WNDinvalidateRect( mHWnd, NULL );
				return 1L;
			}
			break;
		}
		case ECM_GETPROPERTY: 
		{
			qlong property = ECOgetId(eci);			
			EXTfldval fval;
			switch( property )
			{
				case cClock_FaceColor: 			fval.setLong( (qlong)mFaceColor ); break; 			// face color
				case cClock_ShowFace: 			fval.setLong( (qlong)mShowFace ); break; 				// show face
				case cClock_PointsColor: 		fval.setLong( (qlong)mFacePointsColor ); break; // points color
				case cClock_ShowSeconds: 		fval.setLong( (qlong)mShowSecs ); break; 				// show second
				case cClock_SecondsColor: 	fval.setLong( (qlong)mSecondHandColor ); break; // seconds color
				case cClock_ShowMinutes: 		fval.setLong( (qlong)mShowMins ); break; 				// show minutes
				case cClock_MinutesColor: 	fval.setLong( (qlong)mMinuteHandColor ); break; // minutes color
				case cClock_ShowHours: 			fval.setLong( (qlong)mShowHours ); break; 			// show hours
				case cClock_HoursColor: 		fval.setLong( (qlong)mHourHandColor ); break; 	// hours color
				case cClock_ShowIconFace:		fval.setLong( (qlong)mIconFace ); break; 				// show icon face  
				case cClock_ScaleIconFace:  fval.setLong( (qlong)mScaleFace ); break; 			// scale icon face  
				case cClock_IconId:					fval = mIconID; break; 													// icon face icon id // rmm_svg
				case cClock_Seconds:				fval.setLong( mSecs ); break; 									// seconds
				case cClock_Minutes:				fval.setLong( mMins ); break; 									// seconds
				case cClock_Hours:					fval.setLong( mHours ); break; 									// seconds
				case cClock_TimeZoneAdjust: fval.setLong( mAdjustByTimeZone ); break;
				case cClock_TimeZone: 			fval.setLong( mTimeZone ); break;        
				case cClock_IsPM:						fval.setLong( mIsPM ); break;        
				case cClock_Digital:				fval.setLong( mIsDigital ); break;        
				case cClock_DigitalColor:		fval.setLong( mDigiColor ); break;        
				case cClock_24Hour:					fval.setLong( m24Hour ); break;        	// PK6020
			}         
			ECOaddParam(eci,&fval);
			return 1L;
		}
	}
	return 0;
}

double tqfClock::getAngleFromValue( qshort pValue, qshort pSteps )
{
	double stepval1,stepval,angval = -90;
	stepval1 = pValue; stepval = 360/pSteps;
	return angval+=(stepval1*stepval);
}

void tqfClock::drawHand( HDC pHdc, qshort pValue, qshort pSteps, qshort pHandLen, qshort pBackLen, qshort pHandWid )
{                                                                            
	double p1,p2,p3,p4,angle; 
	qpoint p[4]; 
	
	angle = getAngleFromValue( pValue, pSteps ); 
	
	p1 = cos((2*3.14159)*angle/360); 
	p2 = sin((2*3.14159)*angle/360); 
	
	angle-=90; p3 = cos((2*3.14159)*angle/360); p4 = sin((2*3.14159)*angle/360); 

	p[0].h = mCenX - (qshort)( p1 * (double)pBackLen ); p[0].v = mCenY - (qshort)( p2 * (double)pBackLen );
	p[1].h = mCenX + (qshort)( p3 * (double)pHandWid);  p[1].v = mCenY + (qshort)( p4 * (double)pHandWid );
	p[2].h = mCenX + (qshort)( p1 * (double)pHandLen );	p[2].v = mCenY + (qshort)( p2 * (double)pHandLen );
	p[3].h = mCenX - (qshort)( p3 * (double)pHandWid );	p[3].v = mCenY - (qshort)( p4 * (double)pHandWid );

  GDIfillPoly( pHdc, &p[0], 4 );
}

qbool tqfClock::setTimeFromSystem( qbool pDoEvent, EXTCompInfo* eci ) // rmm7000
{                       
	struct tm			*datetime ;

	qbool canSendEvent = ECOisOMNISinTrueRuntime( mHWnd );
	
#ifdef ismobile
	// rmm_mobile: Unix-style time functions are not present on Windows Mobile
	struct tm dts;
	datetime = &dts;
	SYSTEMTIME st;
	GetLocalTime(&st);
	dts.tm_year = dts.tm_mon = dts.tm_mday = dts.tm_wday = dts.tm_yday = 0;	// Not used in this file
	dts.tm_isdst = 0;	// Not used in this file
	dts.tm_hour = st.wHour;
	dts.tm_min = st.wMinute;
	dts.tm_sec = st.wSecond;
	if (mAdjustByTimeZone)
	{
		qlong adj = mTimeZone - 12;
		dts.tm_hour += adj;
		if (dts.tm_hour < 0)
		{
			dts.tm_hour = 24 + dts.tm_hour;
		}
		else if (dts.tm_hour >= 24)
		{
			dts.tm_hour -= 24;
		}
	}
#else
	time_t lTime;
	time(&lTime); 
	if ( mAdjustByTimeZone )
	{
		qlong adj = mTimeZone-12;
		adj *= 60; 
		adj *= 60;
		lTime += adj;
		datetime = localtime(&lTime);
	}
	else
	{
		datetime = localtime(&lTime);
	}
#endif
	HWND theHwnd = mHWnd;	// rmm7000: local, in case sending event deletes the object
	if ( canSendEvent && !mInSendEvent && pDoEvent && mSecs!=datetime->tm_sec && !ECOisDesign( mHWnd ) )
	{
		mSecs = datetime->tm_sec;
		EXTfldval newposparam; newposparam.setLong(datetime->tm_sec);
		mInSendEvent = qtrue;
		ECOsendEvent( mHWnd, cClockEvSecs, &newposparam, 1 );
		if (!ECOfindObject(eci, theHwnd)) return qfalse;	// rmm7000: Detect if object has been deleted
		mInSendEvent = qfalse;
	}
  else mSecs = datetime->tm_sec;
	
	if ( canSendEvent && !mInSendEvent && pDoEvent && mMins!=datetime->tm_min && !ECOisDesign( mHWnd ) )
	{
		mMins = datetime->tm_min;   
		EXTfldval newposparam; newposparam.setLong(datetime->tm_min);
		mInSendEvent = qtrue;
		ECOsendEvent( mHWnd, cClockEvMin, &newposparam, 1 );
		if (!ECOfindObject(eci, theHwnd)) return qfalse;	// rmm7000: Detect if object has been deleted
		mInSendEvent = qfalse;
	}
	else mMins = datetime->tm_min;   
	
	
	qlong newhours = datetime->tm_hour;
	mIsPM = newhours>=12;
	if ( !m24Hour && newhours>=12 ) newhours-=12; // PK6020
	if ( canSendEvent && !mInSendEvent && pDoEvent && mHours!=newhours && !ECOisDesign( mHWnd ) )
	{
		EXTfldval newposparam; newposparam.setLong(newhours);
		mInSendEvent = qtrue;
		ECOsendEvent( mHWnd, cClockEvHours, &newposparam, 1 );
		if (!ECOfindObject(eci, theHwnd)) return qfalse;	// rmm7000: Detect if object has been deleted
		mInSendEvent = qfalse;
	}
	mHours = (qshort)newhours; 
	
	return qtrue; // rmm7000
}

void tqfClock::drawClockFace( HDC pHdc, qrect pFaceRect )
{
	qshort center,cen_x,cen_y,i,i1=0; double w0,v1,v2,angle; 
	qrect r = pFaceRect;
	
	if ( pFaceRect.width() > pFaceRect.height() ) 
		center = ( pFaceRect.height()/2 ) - 4; 
	else 
		center = ( pFaceRect.width()/2 ) - 4;

  cen_x = pFaceRect.width()/2;
  cen_y = pFaceRect.height()/2;
  
  GDIinsetRect( &pFaceRect, 4, 4 );
 
	GDIsetTextColor( pHdc, mFacePointsColor );
	qshort end = 59, inc = 1;
	if ( cen_x<50 || cen_y<50 ) inc = 5;
	for ( i = 0; i<=end; i+=inc ) 
	{
		angle = getAngleFromValue(i,59);
		v1 = cos((2*3.14159)*angle/360); v2 = sin((2*3.14159)*angle/360); 
		if ( inc!=5 && i1==0 ) w0 = 2;
		else w0 = 1;
		r.left = cen_x + (qshort)( ( v1 * (double)center ) - w0 ); 
		r.right = r.left + (qshort)w0;
		r.top = cen_y + (qshort)( ( v2 * (double)center ) - w0 ); 
    r.bottom = r.top + (qshort)w0;
        
		GDIfillRect( pHdc, &r, GDIgetStockBrush( BLACK_BRUSH ) );
		i1++;
		if ( i1==5 ) i1 = 0;
	}              
}

// Start rmm_mobile: Windows mobile seems to fix the colour in the brush once its been used, so we create a new
// brush for each poly fill below.
class CLOCKhandBrush
{
private:
	HDC					mHdc;
	HBRUSH			mBrush;
	HBRUSH			mOldBrush;
public:
	CLOCKhandBrush(HDC pHdc, qcol pColor);
	~CLOCKhandBrush();
};

CLOCKhandBrush::CLOCKhandBrush(HDC pHdc, qcol pColor)
{
#if defined(ismobile) && defined(iswin32)
	mHdc = pHdc;
	mBrush = CreateSolidBrush(pColor);
	mOldBrush = SelectObject(mHdc, mBrush);
#endif
}

CLOCKhandBrush::~CLOCKhandBrush()
{
#if defined(ismobile) && defined(iswin32)
	SelectObject(mHdc, mOldBrush);
	DeleteObject(mBrush);
#endif
}

#ifdef ismobile
	#define CLOCKbitmapDepth 32
#else
	#define CLOCKbitmapDepth 8
#endif
// End rmm_mobile

void tqfClock::updateClock( HDC pHdcOrig, qbool pFillFace, qbool pCreateOffscreen )
{
	qrect r; WNDgetClientRect( mHWnd, &r );
	
	HBITMAP hbmp = NULL; HDC hdc = NULL; HBITMAP oldBmp = NULL;
	
	if ( pCreateOffscreen )
	{
		hbmp = GDIcreateBitmap( r.width(), r.height(), CLOCKbitmapDepth, pHdcOrig ); // rmm_mobile
		hdc = GDIgetTempDC();
		oldBmp = GDIselectBitmap( hdc, hbmp );
	}
	else hdc = pHdcOrig; 

	#if !defined(ismobile) || !defined(iswin32)	// rmm_mobile
		// Start rmm3955: need to use a separate brush selected in the DC, instead of the stock brush which is also used below for filling
		HBRUSH brush = GDIcreateBrush(patFill);
 		HBRUSH oldbrush = GDIselectObject( hdc, brush );
		// End rmm3955
	#endif
 	if (pFillFace)
 	{
 		GDIsetTextColor( hdc, mFaceColor );
		GDIfillRect( hdc, &r, GDIgetStockBrush( BLACK_BRUSH ) );
	}

	if ( mShowFace ) drawClockFace( hdc, r ); 

	qrect facerect; WNDgetClientRect( mHWnd, &facerect );     
	mCenX = facerect.width()/2;
	mCenY = facerect.height()/2;

	qbool bigstate = qtrue;
	if ( mCenX<50 || mCenY<50 ) bigstate = qfalse;
	
	if ( facerect.width() > facerect.height() ) 
		mLastMaxHand = mCenY; 
	else 
		mLastMaxHand = mCenX;

	if ( mShowHours )
	{
		qshort val = ( mHours*5 ) + ( mMins / 12 );
		GDIsetTextColor( hdc, mHourHandColor ); 
		CLOCKhandBrush chb(hdc, GDIgetRealColor(mHourHandColor));	// rmm_mobile
		if ( bigstate ) drawHand( hdc, val, 60, mLastMaxHand-20, 10, 5 );
		else drawHand( hdc, val, 60, mLastMaxHand-10, 7, 3 );
	}
	if ( mShowMins )
	{
		GDIsetTextColor( hdc, mMinuteHandColor ); 
		CLOCKhandBrush chb(hdc, GDIgetRealColor(mMinuteHandColor));	// rmm_mobile
		if ( bigstate ) drawHand( hdc, mMins, 60, mLastMaxHand-5, 10, 5 );
		else drawHand( hdc, mMins, 60, mLastMaxHand-2, 6, 3 );
	}
	if ( mShowSecs )
	{
		GDIsetTextColor( hdc, mSecondHandColor ); 
		CLOCKhandBrush chb(hdc, GDIgetRealColor(mSecondHandColor));	// rmm_mobile
		if ( bigstate ) drawHand( hdc, mSecs, 60, mLastMaxHand-5, 10, 5 );
		else drawHand( hdc, mSecs, 60, mLastMaxHand-2, 6, 3 );
	}
	#if !defined(ismobile) || !defined(iswin32)	// rmm_mobile
		GDIselectObject( hdc, oldbrush );
		GDIdeleteObject(brush);	// rmm3955
	#endif

	if ( pCreateOffscreen )
	{
		// update screen
		ECOexcludeToolTipRect( mHWnd, pHdcOrig );	// PK4712
		GDIcopyBits( hdc, pHdcOrig, &r, &r, stretch() ); // rmm_mobile
		GDIselectBitmap( hdc, oldBmp );
		GDIdeleteBitmap( hbmp );
	}
}

void tqfClock::drawDigits( qbool pIsHours, qshort pValue, qrect* pRect, HDC pDst )
{
	qrect r1;
	qshort id = 0;
	if (pIsHours && pValue==0 && !m24Hour) pValue = 12; // rmm5791: check m24Hour
	id = pValue/10;
	// Start rmm_mobile
	qrect drawRect(*pRect);
	#if defined(ismobile) || defined(iswin32) // rmm9011
		GDIconvToScreen(&drawRect);
	#endif
	r1 = getDigitRect( id ); 
	{
		GDIdisableScaling ds;
		GDIdrawAlphaBitmap(pDst, mDigiBitmap, &r1, &drawRect, stretch(), 1);	// rmm10067
		GDIoffsetRect( pRect, 18, 0 );
	}
	id = pValue-(id*10);
	drawRect = *pRect;
	#if defined(ismobile) || defined(iswin32) // rmm9011
		GDIconvToScreen(&drawRect);
	#endif
	r1 = getDigitRect( id ); 
	{
		GDIdisableScaling ds;
		GDIdrawAlphaBitmap(pDst, mDigiBitmap, &r1, &drawRect, stretch(), 1);	// rmm10067
		GDIoffsetRect( pRect, 18, 0 );
	}
	// End rmm_mobile
}

void tqfClock::drawGap( qrect* pRect, HDC pDst )
{
	qrect r2; r2.top = 0; r2.left = mSecs & 1 ? 181 : 176;  r2.right = mSecs & 1 ? 184 : 179; r2.bottom = 31;
	qrect r3; r3 = r2; r3.left = pRect->left+1; r3.right = r3.left + 4;
	// Start rmm_mobile
	qrect drawRect(r3);
	#if defined(ismobile) || defined(iswin32) // rmm9011
		GDIconvToScreen(&drawRect);
	#endif
	GDIdisableScaling ds;
	// End rmm_mobile
	GDIdrawAlphaBitmap(pDst, mDigiBitmap, &r2, &drawRect, stretch(), 1);	// rmm10067
	GDIoffsetRect( pRect, 8, 0 ); 
}

void tqfClock::drawAMPM( qrect* pRect, HDC pDst )
{
	if ( m24Hour ) return; // PK6020
	pRect->top = 10; pRect->bottom = 20;
	pRect->left+=3; pRect->right = pRect->left + 13;
	qrect r2; r2.left = 163;  r2.right = 176;
	if ( mIsPM )
	{		
		r2.top = 3;  r2.bottom = 13; 
	}
	else 
	{	
		r2.top = 17; r2.bottom = 27; 
	}
	// Start rmm_mobile
	qrect drawRect(*pRect);
	#if defined(ismobile) || defined(iswin32) // rmm9011
		GDIconvToScreen(&drawRect);
	#endif
	GDIdisableScaling ds;
	// End rmm_mobile
	GDIdrawAlphaBitmap(pDst, mDigiBitmap, &r2, &drawRect, stretch(), 1);	// rmm10067
}

void tqfClock::digitalClockPaint( HDC pHdc )
{
	qrect cRect; WNDgetClientRect( mHWnd, &cRect );
	
	qbool needsep = qfalse;qshort maxwid = 0;
	if ( mShowHours ) { maxwid+=36; needsep = qtrue; }
	if ( mShowMins ) { if ( needsep ) maxwid+=8; maxwid+=36; needsep = qtrue; }
	if ( mShowSecs ) { if ( needsep ) maxwid+=8; maxwid+=36; needsep = qtrue; }
	maxwid+=14;
	
	HDC hdc; HRESERVED hpal; GDIcreateScreenDC( &hdc, &hpal );
	qrect offScrn; offScrn.left = offScrn.top = 0; offScrn.right = maxwid-1; offScrn.bottom = 31;
	HBITMAP hbmp = GDIcreateBitmap( maxwid, 32, 0 );
	HBITMAP oldBmp = GDIselectBitmap( hdc, hbmp );
	GDIsetTextColor( hdc, mFaceColor );
	GDIfillRect( hdc, &offScrn, GDIgetStockBrush( BLACK_BRUSH ) );

	#ifndef iswin32 // rmm9011
		GDIdeviceScale* scale = new GDIdeviceScale(hdc);  //pkcocoa_1082
	#endif

  // draw digits
  qrect digitRect; digitRect.left = digitRect.top = 0; digitRect.bottom = 31; digitRect.right = 15;
  if ( mShowHours )
  	drawDigits( qtrue, mHours, &digitRect, hdc );  
  	
  if ( mShowMins )
  {    
  	if ( mShowHours ) 
  		drawGap( &digitRect, hdc );
  	drawDigits( qfalse, mMins, &digitRect, hdc );
  }
  if ( mShowSecs )
  {
  	if ( mShowMins || ( !mShowMins && mShowHours ) ) 
  		drawGap( &digitRect, hdc );
    drawDigits( qfalse, mSecs, &digitRect, hdc );
  }                              
  drawAMPM( &digitRect, hdc );
  
	#ifndef iswin32 // rmm9011
		delete scale; // pkcocoa_1082
	#endif

	ECOexcludeToolTipRect( mHWnd, pHdc );	// PK4712

	// to screen
	if ( mScaleFace ) 
		GDIcopyBits( hdc, pHdc, &offScrn, &cRect, qtrue );
	else
	{
		qrect cRect1 = cRect;
		qshort x = (cRect.width()/2)-(offScrn.width()/2);
		qshort y = (cRect.height()/2)-(offScrn.height()/2);
	 	HBRUSH oldbrush = GDIselectObject( hdc, GDIgetStockBrush( BLACK_BRUSH ) );
		GDIsetTextColor( pHdc, mFaceColor );
		GDIinsetRect( &cRect, -1, -1 );
	 	qrgn* clip = GDIcreateRectRgn( &cRect );
		cRect = offScrn; GDIoffsetRect( &cRect, x, y );
	 	qrgn* rgn1 = GDIcreateRectRgn( &cRect );
	 	GDIcopyBits( hdc, pHdc, &offScrn, &cRect, stretch() ); // rmm_mobile
		GDIrgnXor( clip, rgn1, clip );
		GDIdeleteRgn(rgn1);	// rmm6473

		GDIsetClipRgn( pHdc, clip );
		GDIfillRect( pHdc, &cRect1, GDIgetStockBrush( BLACK_BRUSH ) );
		GDIdeleteRgn(clip); // rmm6473
	 	GDIselectObject( hdc, oldbrush );
	}
	GDIselectBitmap( hdc, oldBmp );
	GDIdeleteBitmap( hbmp );         
	GDIdeleteScreenDC( hdc, hpal );
}                                            
                                            
void tqfClock::iconClockPaint( HDC pHdc )
{   
	EXTBMPref bmp(mIconID, mApp); // MHWEB // rmm_svg3
	{
		qrect r; WNDgetClientRect(mHWnd, &r);
		ePicSize psize = EXTBMPref::getBmpSize(mIconID);
		HBITMAP hbmp = GDIcreateBitmap(r.width(), r.height(), CLOCKbitmapDepth, pHdc); // rmm_mobile
		HDC hdc = GDIgetTempDC();
		HBITMAP old = GDIselectBitmap(hdc, hbmp);
		// fill first with face color
		GDIsetTextColor(hdc, mFaceColor);
		GDIfillRect(hdc, &r, GDIgetStockBrush(BLACK_BRUSH));
		// draw icon scaled or centered
		GDIsetTextColor(hdc, mFacePointsColor);	// rmm_svg3
		qrect r1 = r;
		bmp.draw(hdc, &r1, psize, picNormal, qfalse, colNone, mScaleFace, jstCenter, jstCenter);
		// draw hands
		updateClock(hdc, qfalse, qfalse);
		// update screen

		ECOexcludeToolTipRect(mHWnd, pHdc);	// PK4712

		GDIcopyBits(hdc, pHdc, &r, &r, stretch()); // rmm_mobile
		GDIselectBitmap(hdc, old);
		GDIdeleteBitmap(hbmp);
	}
}

qbool tqfClock::paint(EXTCompInfo* eci)	// rmm7000
{
	if (!setTimeFromSystem( qfalse, eci )) return qtrue; // rmm7000
	
	WNDpaintStruct paintStruct;
	WNDbeginPaint( mHWnd, &paintStruct );
	if ( mIsDigital )
		digitalClockPaint( paintStruct.hdc );
	else if ( mIconFace )
		iconClockPaint( paintStruct.hdc );
	else
		updateClock( paintStruct.hdc, qtrue, qtrue );
	#ifndef ismobile	// rmm_mobile
		GDIclearClip(paintStruct.hdc);							// rmm5006
		drawDesignNumber(paintStruct.hdc);					// rmm4999
		ECOdrawMultiKnobs(mHWnd, paintStruct.hdc);	// rmm5006
	#endif
	WNDendPaint( mHWnd, &paintStruct );	
	return qtrue;
}

void tqfClock::drawDesignNumber(HDC pHdc) // rmm4999
{
	if (ECOisShowNumber(mHWnd))
	{
		qrect r; 
		WNDgetClientRect(mHWnd, &r); 
		ECOdrawNumberEx(mHWnd, pHdc, qtrue);
	}
}
 
#define CLOCK_TIMERID		100
                    
extern "C" LRESULT OMNISWNDPROC GenericWndProc( HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, EXTCompInfo* eci )
{
   ECOsetupCallbacks(hwnd,eci);
	 switch (Msg)
	 {
			case WM_TIMER:							
			{	           
				tqfClock* object = (tqfClock*)ECOfindObject( eci, hwnd );
				if ( object && wParam==CLOCK_TIMERID)
				{ // Found object and the timer event is our event (as opposed to a tooltip timer event for example)
					if (!object->setTimeFromSystem( qtrue, eci )) return qfalse; // rmm7000
					HDC hdc = WNDstartDraw( hwnd );
					if ( object->isDigitalClock() ) object->digitalClockPaint( hdc );
					else if ( object->isIconFace() ) object->iconClockPaint( hdc ); 
					else object->updateClock( hdc, qtrue, qtrue ); 
					#ifndef ismobile	// rmm_mobile
						GDIclearClip(hdc); // rmm5006
						object->drawDesignNumber(hdc);	// rmm4999
						ECOdrawMultiKnobs(hwnd, hdc);		// rmm5006
					#endif
					WNDendDraw( hwnd, hdc );
					return qfalse; // AE4837
				}
				break; // AE4837
      }
			case WM_WINDOWPOSCHANGED:
			{
				// Start rmm_mobile
				WNDwindowPosMessageStruct *wpos = (WNDwindowPosMessageStruct *)lParam;
				if (wpos->size() || wpos->frameChange())
				{
					// End rmm_mobile
					tqfClock* object = (tqfClock*)ECOfindObject( eci, hwnd );
					if ( object ) WNDinvalidateRect( hwnd, NULL );
				}
				break;
			}
			case WM_PAINT:							
			{
				tqfClock* object = (tqfClock*)ECOfindObject( eci, hwnd );
				if ( NULL!=object && object->paint(eci) ) // rmm7000
					return qtrue;
				break;
			}
			case WM_ERASEBKGND:	// rmm_mobile
			{
				return qtrue;
			}
			case ECM_OBJCONSTRUCT:				/* Construct an object */
			{
				tqfClock* object = new tqfClock( hwnd );
				ECOinsertObject( eci, hwnd, (void*)object );
				object->mApp = ECOgetApp( eci->mInstLocp );	 // MHWEB
				WNDsetTimer( hwnd, CLOCK_TIMERID, 500 );
				return qtrue;
			}
			case ECM_OBJDESTRUCT:					/* Destruct the object */
			{
				WNDkillTimer( hwnd, CLOCK_TIMERID );
				tqfClock* object = (tqfClock*)ECOremoveObject( eci, hwnd );
				if ( NULL!=object )
					delete object;
				return qtrue;
			}
			case ECM_METHODCALL:				/* Object: Function Call */
			{
				return qfalse;
			}
			case ECM_PROPERTYCANASSIGN:  	/* Object: Is the property assignable (ie readonly?) */
			case ECM_SETPROPERTY: 				/* Object: Assignment to a property */
			case ECM_GETPROPERTY:					/* Object: Retrieve value from property */
			{
				tqfClock* object = (tqfClock*)ECOfindObject( eci, hwnd );
				if ( object )
				{
					return object->attributeSupport( Msg, wParam, lParam, eci );
				}
				return 0L;
			}
      case ECM_GETCOMPLIBINFO:
      {
      	return ECOreturnCompInfo( gInstLib, eci, LIB_RES_NAME, COMPONENT_COUNT );
      }
			case ECM_GETCOMPICON:
			{ 	
				if ( eci->mCompId==CLOCK_ID ) return ECOreturnIcon( gInstLib, eci, CLOCK_ICON );
				return qfalse;
			}
			case ECM_GETCONSTNAME:
			{
				return ECOreturnConstants( gInstLib, eci, 7000, 7027 );
			}
			case ECM_GETCOMPID:
			{
				if ( wParam==1 )
					return ECOreturnCompID( gInstLib, eci, CLOCK_ID, cObjType_Basic );
				return 0L;
			}
			case ECM_GETEVENTNAME:
			{
				return ECOreturnEvents(gInstLib,eci,&CLOCKevents[0],3);
			}
			case ECM_GETPROPNAME:
			{
				return ECOreturnProperties( gInstLib, eci, &CLOCKproperties[0], 21 );
			}                                                                               
// MHWEB begins.
			case ECM_GETVERSION:	
			{
				return ECOreturnVersion (gInstLib);
			}                                                                 
#ifdef isRCCDESIGN
	 		case ECM_CONNECT:
      {
		    return EXT_FLAG_LOADED|EXT_FLAG_ALWAYS_USABLE|EXT_FLAG_REMAINLOADED; // Return external flags	// rmm_thindl
      } 			
#endif
// MHWEB ends.			
			case ECM_ISUNICODE:	// rmmuni
			{
				return qtrue;
			}
	 }
	 return WNDdefWindowProc(hwnd,Msg,wParam,lParam,eci);
}

	
